代码之家  ›  专栏  ›  技术社区  ›  Yair Halberstadt

使用yield作为上下文关键字会引起问题吗

  •  1
  • Yair Halberstadt  · 技术社区  · 7 年前

    Essential C# 它指出:

    在C#1.0之后,没有向C#引入新的保留关键字。然而, 在以后的版本中,有些构造使用上下文关键字,这些关键字是 仅在特定位置有效。在这些指定的 方法,大多数C#1.0代码都与以后的标准兼容。

    将yield指定为关键字,微软发布了alpha版本 成千上万的开发商。然而,语言设计者最终 确定通过使用收益率而不是收益率,他们可以 它的特殊意义就在它的附近。

    现在我不明白这一点,就像在c#2.0之前一样,每个返回IEnumerable的方法中都必须有一个return语句,而yield只能在返回IEnumerable但没有return语句的方法中用作上下文关键字。如

    public IEnumerable<int> GetInts()
    {
        for (int i = 0; i < 1000; i++)
            yield i;
    }
    

    因为这个方法不会编译C#2.0之前的版本,所以我看不出它怎么会破坏向后兼容。

    所以我的问题是:

    是否存在使用 yield yield return 在C中#会破坏向后兼容性,或者导致问题?

    2 回复  |  直到 7 年前
        1
  •  3
  •   Community Mohan Dere    6 年前

    问题

    for (int i = 0; i < 1000; i++)
        yield i;
    

    如果没有yield关键字,这确实是无效的,但是如果在 i

    for (int i = 0; i < 1000; i++)
        yield (i);
    

    现在这是一个名为 yield . 所以如果我们解释 yield (i); ,此有效代码的含义将更改,从而破坏向后兼容性。

    一个更正式的方法是这样的:如果我们把C#2的语法改成 statement: 'yield' 'return' expression ';' 具有 statement: 'yield' expression ';' ,则该规则与函数调用规则之间存在歧义,因为 expression 可导出为 '(' expression ')' 'yield' '(' expression ')' ';'

    可能的解决方案1

    你当然只能这么说 yield i; (或任何其他不以左括号开头的表达式)应解释为在 产量(i);

    这也意味着将上述语法规则改为 statement: 'yield' expressionNoStartingParen ';' 然后定义 expressionNoStartingParen 表达

    可能的解决方案2

    yield expression; 在没有return语句的非void方法中作为yield语句。这将保持向后兼容性,因为这样的方法在C#1中无论如何都是无效的。然而,这可能有点不一致,因为现在可以定义一个名为yield的方法,并在不使用yield语句的方法中调用它,但不能在使用yield语句的方法中调用它。

    yield(x); 是一个仅通过查看该行的收益声明(您需要查看整个方法);解析器也不会——它必须知道该方法是否包含 return 声明。这将需要对语法中有返回和无返回的实体有两个不同的定义,并对每个实体中允许作为标识符的内容有一个单独的定义。这将是一个可怕的语法看和实施。

    在实践中,很可能会创建一个模棱两可的语法,然后解析 yield (x);

    结论

    因此,总之,这两种解决这个问题的方法都会导致一些不一致,后者也很难实施。只治疗 产量 返回 避免了歧义而不产生任何不一致,并且易于实现。

        2
  •  0
  •   Yair Halberstadt    7 年前

    如。

    public class yield
    {
    
    }
    ...
    public IEnumerable<yield> GetInts()
    {
        yield item;
        item = new yield(); //compiler complains - item not declared.
    
        yield item2 = new yield(); //compiler complains-item2 not declared.
    }
    

    public int yield(int x) => 5;
    public IEnumerable<int> GetInts()
    {
        yield (5); //does not call the yield method as expected, but yields 5 instead
    }
    

    因此,尽管这些方法都不会编译C#2.0之前的版本,但使用收益率回报率回避了所有这些问题。