Компилятор С# не распознает методы возврата доходности как похожие?

Если у меня есть два метода 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

Я получаю сообщение об ошибке

Тип условного выражения не может быть определен, потому что существует нет неявного преобразования между "группой методов" и "группой методов"

Тем не менее, явное действие cast:

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

Мне ничего не хватает или это ошибка в компиляторе С# (я использую VS2010SP1)?

Примечание. Я прочитал this и по-прежнему считаю, что первый должен быть скомпилирован отлично.

EDIT: удалено использование var в фрагментах кода, поскольку это не то, что я хотел спросить.

Ответ 1

Нет. Это не ошибка. Он не имеет ничего с yield. Дело в том, что тип выражения method group может быть преобразован в тип delegate только тогда, когда он назначен непосредственно как: SomeDel d = SomeMeth.

Спецификация С# 3.0:

§6.6 Преобразование групп методов

Неявное преобразование (§6.1) существует из группы методов (п. 7.1) к совместимый тип делегата.

Это единственное неявное преобразование, возможное с группами методов.

Как тернарный оператор оценивается по типам:

A ? B : C:

Убедитесь, что либо B, либо C можно неявно перевести на другой тип. Например A ? 5 : 6.0 будет double, потому что 5 может быть неявно отбрасываться на double. Тип A и B в этом случае равен method group, и между method group нет преобразования. Только делегировать, и он может быть применен так же, как и вы.

Ответ 2

Существует много возможных типов делегатов, которые могут соответствовать сигнатуре методов EvenNumbers и OddNumbers. Например:

  • Func<int, IEnumerable<int>>
  • Func<int, IEnumerable>
  • Func<int, object>
  • любое количество пользовательских типов делегатов

Компилятор не будет пытаться угадать, какой совместимый тип делегата вы ожидаете. Вам нужно быть явным и сказать это - с актом в вашем примере - именно тот тип делегата, который вы хотите использовать.

Ответ 3

Хорошо даже

var gen = OddNumbers;

не работает. Поэтому вы не можете ожидать, что тернарный оператор будет работать.

Я думаю, что var не может вывести тип делегата.

Ответ 4

yield Return не имеет ничего общего с этим.

Вы не устанавливаете generator в IEnumerable<int>, вы устанавливаете его в MethodGroup, то есть функцию без скобок для совершения вызова.

Второй оператор отличает MethodGroup to Delegate, который можно сравнить.

Возможно, вы хотите сделать что-то вроде, но

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

Я не мог сказать точно.

Ответ 5

он не имеет ничего общего с итераторами, тот же код не компилируется, если методы являются простыми функциями. Компилятор неохотно автоматически конвертирует метод в объект-делегат, забыв использовать метод() в вызове метода, является слишком распространенной ошибкой. Вы должны сделать это явно.

Ответ 6

Накопление того, что работает и не работает:

Не работает:

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, последнее также должно завершиться неудачей.

Мое предположение - проблема с тернарным оператором.

Ответ 7

Проблема состоит в том, что утверждение

var gen = OddNumbers;

Можно интерпретировать как

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

и

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

Компилятор не может решить это, поэтому вам нужно это сделать.

Ответ 8

Метод (группа методов) не имеет встроенного типа, только делегаты. Вот почему тернарный оператор не может вывести возвращаемый тип, поэтому вы должны указать одно или другое возвращаемое значение как тип, который хотите вернуть.