Компилятор C # не распознает методы возврата дохода как похожие? - PullRequest
10 голосов
/ 22 июля 2011

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

Примечание: я прочитал это и все еще считаю, что первый должен был скомпилироваться нормально.

РЕДАКТИРОВАТЬ: Удалено использование var в фрагментах кода, поскольку это было не то, что я хотел спросить.

Ответы [ 8 ]

6 голосов
/ 22 июля 2011

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

C # 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 нет преобразования.Только делегировать, и это может быть применено, как вы сделали.

6 голосов
/ 22 июля 2011

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

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

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

1 голос
/ 22 июля 2011

Сводка того, что работает, а что нет:

Не работает:

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

Мне кажется, проблема с троичным оператором.

1 голос
/ 22 июля 2011

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

1 голос
/ 22 июля 2011

yield Return не имеет к этому никакого отношения.

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

Второе утверждение приводит MethodGroup s к Delegate s, которые можно сравнить.

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

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

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

1 голос
/ 22 июля 2011

ну даже

var gen = OddNumbers;

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

Полагаю, var не может определить тип делегата.

0 голосов
/ 22 июля 2011

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

0 голосов
/ 22 июля 2011

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

var gen = OddNumbers;

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

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

и

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...