Компилятор C# не распознает методы возврата yield как аналогичные?
Если у меня есть два метода 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)?
Примечание: я прочиталэто и все еще считаю, что первый должен был быть составлен отлично.
EDIT: убрал использование var
в фрагментах кода, поскольку это было не то, что я собирался спросить.
8 ответов:
Нет. Это не ошибка. Он не имеет ничего общего с
yield
. Дело в том, что тип выраженияmethod group
может быть преобразован в типdelegate
только тогда, когда он присваивается непосредственно как:SomeDel d = SomeMeth
.§6.6 метод групповых преобразований
Неявное преобразование (§6.1) существует из группы методов (§7.1) в совместимый тип делегата.
Это единственное неявное преобразование, возможное с группами методов.
Как тернарный оператор оценивается в терминах типов умозаключений:
A ? B : C
:Убедитесь, что либо
B
, либоC
могут быть неявно приведены к типу друг друга. Например,A ? 5 : 6.0
будетdouble
, потому что 5 может быть неявно приведено кdouble
. ТипA
иB
в этом случае являетсяmethod group
, и нет никакого преобразования междуmethod group
. Только делегировать, и его можно принудить, как вы это сделали.
Существует множество возможных типов делегатов, которые могут соответствовать сигнатуре методов
EvenNumbers
иOddNumbers
. Например:Компилятор не будет пытаться угадать, какой тип совместимого делегата вы ожидаете. Вам нужно быть явным и сказать ему-с приведением в вашем примере-какой именно тип делегата вы хотите использовать.
Func<int, IEnumerable<int>>
Func<int, IEnumerable>
Func<int, object>
- любое количество пользовательских типов делегатов
Ну даже
var gen = OddNumbers;
Не работает. Поэтому вы не можете ожидать, что троичный оператор будет работать.
Я думаю, что var не может определить тип делегата.
yield Return
не имеет к этому никакого отношения.Вы не устанавливаете
generator
наIEnumerable<int>
, вы устанавливаете его наMethodGroup
, то есть функцию без скобок, чтобы сделать вызов.Второе утверждение приводит
MethodGroup
s кDelegate
s, которые можно сравнить.Возможно, вы хотите сделать что-то вроде но,
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;
Если бы это было как-то связано с
yield
илиvar
, последнее также должно было бы потерпеть неудачу.Мое предположение-это проблема с тернарным оператором.