Компилятор 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, то есть функцию без скобок, чтобы сделать вызов.Второе утверждение приводит
MethodGroups кDelegates, которые можно сравнить.Возможно, вы хотите сделать что-то вроде но,
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, последнее также должно было бы потерпеть неудачу.Мое предположение-это проблема с тернарным оператором.