Как я могу назначить Func <> условно между лямбдами, используя условный тернарный оператор? - PullRequest
45 голосов
/ 04 ноября 2008

Как правило, при использовании условного оператора, вот синтаксис:

int x = 6;
int y = x == 6 ? 5 : 9;

Ничего особенного, довольно прямолинейно.

Теперь давайте попробуем использовать это при назначении лямбды типу Func. Позвольте мне объяснить:

Func<Order, bool> predicate = id == null
    ? p => p.EmployeeID == null
    : p => p.EmployeeID == id;

Это тот же синтаксис, и должен работать? Правильно? По какой-то причине это не так. Компилятор выдает это загадочное сообщение:

Ошибка 1 Невозможно определить тип условного выражения, поскольку не существует неявного преобразования между «лямбда-выражением» и «лямбда-выражением»

Затем я изменил синтаксис и таким образом он сделал сработал:

Func<Order, bool> predicate = id == null
    ? predicate = p => p.EmployeeID == null
    : predicate = p => p.EmployeeID == id;

Мне просто любопытно, почему это не работает в первую очередь?

(Примечание: мне не понадобился этот код, поскольку я обнаружил, что при сравнении значения int с нулем вы просто используете object.Equals)

Ответы [ 3 ]

44 голосов
/ 04 ноября 2008

Вы можете преобразовать лямбда-выражение в конкретный целевой тип делегата, но для определения типа условного выражения компилятору необходимо знать тип каждого из второго и третьего операндов. Хотя они оба являются просто «лямбда-выражением», преобразования из одного в другое не происходит, поэтому компилятор не может сделать ничего полезного.

Однако я бы не советовал использовать назначение - приведение более очевидно:

Func<Order, bool> predicate = id == null 
    ? (Func<Order, bool>) (p => p.EmployeeID == null)
    : p => p.EmployeeID == id;

Обратите внимание, что вам нужно предоставить его только для одного операнда, чтобы компилятор мог выполнить преобразование из другого лямбда-выражения.

6 голосов
/ 04 ноября 2008

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

Func<Order, bool> predicate = 
    id == null ? 
        new Func<Order,bool>(p => p.EmployeeID == null) :
        new Func<Order,bool>(p => p.EmployeeID == id);

но это просто отстой, Вы также можете попробовать

Func<Order, bool> predicate = 
    id == null ? 
        (Order p) => p.EmployeeID == null :
        (Order p) => p.EmployeeID == id;
1 голос
/ 16 января 2018

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

Мой Find метод является универсальным методом, который получает Expression<Func<T, bool>> в качестве предиката и дает List<T> в качестве вывода.
Я хотел найти страны, но мне нужны все, если список языков был пуст, и отфильтрованный список, если список языков был заполнен. Сначала я использовал код, как показано ниже:

var countries= 
Find(languages.Any() 
  ? (country => languages.Contains(country.Language))
  : (country => true));

Но именно я получаю ошибку: there is no implicit conversion between lambda expression and lambda expression.

Проблема заключалась в том, что у нас есть только два лямбда-выражения, и ничего больше, например, что такое country => true точно ?? Мы должны определить тип хотя бы одного из лямбда-выражений . Если будет определено только одно из выражений, ошибка будет пропущена. Но чтобы сделать код более читабельным, я извлек оба лямбда-выражения и вместо этого использовал переменную, как показано ниже:

   Expression<Func<Country, bool>> getAllPredicate = country => true;
   Expression<Func<Country, bool>> getCountriesByLanguagePredicate = country => languages.Contains(country.Language);

   var countries= Find(languages.Any()
                       ? getCountriesByLanguagePredicate
                       : getAllPredicate);

Подчеркну, что, если я просто определю один из типов выражения, ошибка будет исправлена.

...