C#编译器没有将yield return方法识别为类似?

时间:2011-07-22 11:50:39

标签: c# compiler-construction visual-studio-2010-sp1 yield-return compiler-bug

如果我有两个具有相同签名的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

我收到错误消息

  

由于存在,因此无法确定条件表达式的类型   “方法组”和“方法组”之间没有隐式转换

然而,一个明确的演员工作:

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

我错过了什么或者这是C#编译器中的错误(我使用的是VS2010SP1)?

注意:我已阅读this并仍然相信第一个应该编译得很好。

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

8 个答案:

答案 0 :(得分:6)

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

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

编译器不会尝试猜测您期望的兼容委托类型。您需要明确并告诉它 - 在您的示例中使用强制转换 - 确切地说您要使用哪种委托类型。

答案 1 :(得分:6)

没有。这不是一个bug。 yield没有任何内容。问题是表达式类型method group只有在直接分配时才能转换为delegate类型:SomeDel d = SomeMeth

C# 3.0 specification

§6.6方法组转化

  

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

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

如何根据类型推断评估三元运算符:

A ? B : C

确保BC可以隐式转换为彼此的类型。例如,A ? 5 : 6.0将为double,因为5可以隐式转换为double。在这种情况下,AB的类型为method groupmethod group之间没有转化。只有代表才可以像你一样强制执行。

答案 2 :(得分:1)

甚至

var gen = OddNumbers;

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

我猜var不能推断委托类型。

答案 3 :(得分:1)

yield Return与此无关。

您没有将generator设置为IEnumerable<int>,而是将其设置为MethodGroup,即没有括号的功能可以拨打电话。

第二个语句将MethodGroup转换为可以比较的Delegate

也许你的意思是做某事,但是,

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

我不能肯定地说。

答案 4 :(得分:1)

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

答案 5 :(得分: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有任何关系,后者也应该失败。

我的猜测是三元运算符的问题。

答案 6 :(得分:0)

问题在于声明

var gen = OddNumbers;

可以解释为

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

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

编译器无法决定,所以你必须这样做。

答案 7 :(得分:0)

方法(方法组)没有固有类型,只有委托才有。这就是为什么三元运算符无法推断要返回的类型的原因,因此您必须将一个或另一个返回值强制转换为要返回的类型。