c#编译器不能识别类似的yield返回方法

本文关键字:yield 返回 方法 编译器 不能 识别 | 更新日期: 2023-09-27 18:03:14

如果我有两个具有相同签名的yield return方法,编译器似乎不会识别它们是相似的。

我有两个这样的yield return方法:

    public static IEnumerable<int> OddNumbers(int N)
    {
        for (int i = 0; i < N; i++)
            if (i % 2 == 1) yield return i;
    }
    public static IEnumerable<int> EvenNumbers(int N)
    {
        for (int i = 0; i < N; i++)
            if (i % 2 == 0) yield return i;
    }
有了这个,我希望下面的语句可以很好地编译:

Func<int, IEnumerable<int>> generator = 1 == 0 ? EvenNumbers : OddNumbers; // Does not compile

我得到错误信息

不能确定条件表达式的类型,因为有"方法组"answers"方法组"之间没有隐式转换

但是,显式强制转换可以工作:

Func<int, IEnumerable<int>> newGen = 1 == 0 ? (Func<int, IEnumerable<int>>)EvenNumbers : (Func<int, IEnumerable<int>>)OddNumbers; // Works fine

我错过了什么或这是一个bug在c#编译器(我使用VS2010SP1)?

注意:我读了这篇文章,仍然认为第一个应该编译得很好。

编辑:删除了var在代码片段中的使用,因为这不是我想要问的。

c#编译器不能识别类似的yield返回方法

No。这不是一个bug。它与yield没有任何关系。问题是表达式类型method group只有在直接赋值时才能转换为delegate类型,如:SomeDel d = SomeMeth .

c# 3.0规范:

§6.6方法组转换

存在从方法组(第7.1节)到a的隐式转换(第6.1节)兼容委托类型。

这是方法组唯一可能的隐式转换。

如何根据类型推断计算三元操作符:

A ? B : C:

确保BC可以隐式转换为彼此的类型。例如,A ? 5 : 6.0将是double,因为5可以隐式转换为double。在本例中,AB的类型为method group, method group之间没有转换。只有委派,它可以强制执行,因为你做了

有许多可能的委托类型可以匹配EvenNumbersOddNumbers方法的签名。例如:

  • Func<int, IEnumerable<int>>
  • Func<int, IEnumerable>
  • Func<int, object>
  • 任意数量的自定义委托类型

编译器不会尝试猜测您期望的兼容委托类型。您需要显式地告诉它—在您的示例中使用强制类型转换—您想要使用哪种委托类型。

甚至

var gen = OddNumbers;

不起作用。所以你不能指望三元运算符工作。

我猜var不能推断委托类型

yield Return与此无关。

您没有将generator设置为IEnumerable<int>,您将其设置为MethodGroup,即没有括号的函数进行调用。

第二个语句将MethodGroup s转换为Delegate s,以便进行比较。

也许你的意思是做一些像but,

var generator = 1 == 0 ? EvenNumbers(1) : OddNumbers(1);

我不能肯定。

与迭代器没有任何关系,如果方法是简单函数,同样的代码将无法编译。编译器不愿意自动将方法转换为委托对象,忘记在方法调用中使用()是非常常见的错误。

工作和不工作的汇总:

不工作:

var generator = 1 == 0 ? EvenNumbers : OddNumbers;
Func<int, IEnumerable<int>> generator = 1 == 0 ? EvenNumbers : OddNumbers;

工作:

var generator = 1 == 0 ? (Func<int, IEnumerable<int>>)EvenNumbers : OddNumbers;

如果它与yieldvar有关,后者也应该失败。

我猜是三元运算符的问题

问题是语句

var gen = OddNumbers;

可以同时解释为

Func<int, IEnumerable<int>> gen = OddNumbers;

Expression<Func<int, IEnumerable<int>> gen = OddNumbers;

编译器不能决定这个,所以你必须这样做。

方法(方法组)没有内在类型,只有委托有。这就是为什么三元操作符不能推断要返回的类型,因此必须将一个或另一个返回值强制转换为要返回的类型的原因。