C#编译器无法识别类似的yield返回方法?

问题描述 投票:0回答:8

如果我有两个具有相同签名的

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
的用法,因为这不是我想要问的。

c# visual-studio-2010 compiler-bug yield-return
8个回答
6
投票

不。这不是一个错误。它与

yield
没有任何关系。问题是,表达式类型
method group
只有在直接赋值时才能转换为
delegate
类型,例如:
SomeDel d = SomeMeth

C# 3.0 规范

§6.6 方法组转换

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

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

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

A ? B : C

确保

B
C
可以隐式转换为彼此的类型。例如
A ? 5 : 6.0
将是
double
,因为 5 可以隐式转换为
double
。在这种情况下,
A
B
的类型是
method group
,并且
method group
之间没有转换。只需委托即可执行,就像您所做的那样。


6
投票

有许多可能的委托类型可以与

EvenNumbers
OddNumbers
方法的签名相匹配。例如:

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

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


1
投票

好吧

var gen = OddNumbers;

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

我猜 var 无法推断委托类型。


1
投票

yield Return
与此无关。

您没有将

generator
设置为
IEnumerable<int>
,而是将其设置为
MethodGroup
,即不带括号进行调用的函数。

第二个语句将

MethodGroup
转换为可以比较的
Delegate

也许你想做一些类似但是的事情,

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

我不能肯定地说。


1
投票

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


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;

如果与

yield
var
有关,后者也应该失败。

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


0
投票

问题在于声明

var gen = OddNumbers;

可以同时解释为

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

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

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


0
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.