Ошибка компилятора для выражений / перегруженных функций
Скриншот говорит об этом в значительной степени. У меня есть перегрузки, как видно на скриншоте. При использовании строки в качестве второго параметра компилятор должен выяснить, что первый аргумент может быть только Func, а не выражением. Но компилятор выдает ошибку, говоря: "Выражение lamda с телом оператора не может быть преобразовано в дерево выражений".
Почему компилятор не может определить правильную перегрузку?
Явное приведение не помогает. Что работает, когда я делаю локальную переменную типа Func, а затем использую это вместо.
Используемая среда - FakeItEasy 1.24.0.
РЕДАКТИРОВАТЬ:
Вот код, который показывает поведение:
public static void Main(string[] args)
{
//compiler error
A.CallTo(() => Main(A<string[]>.That.Matches(strings =>
{
return true;
}, "description")));
//compiles
Func<string[], bool> predicate = strings =>
{
return true;
};
A.CallTo(() => Main(A<string[]>.That.Matches(predicate, "description")));
Console.ReadLine();
}
1 ответ
Вопрос не в обращении к Matches
, Это в вызове CallTo
, который ожидает Expression<Action>
,
Видимо Expression
не только не может быть лямбда-выражением с телом оператора, но также не может содержать лямбда-выражение с телом оператора.
(Я не уверен, будет ли работать ваше решение "поместить лямбду в локальную переменную", или оно просто обманывает компилятор и не будет работать во время выполнения.)
Вот тест, который я собрал:
static void Overloaded(Action a, string param) { }
static void Overloaded(Expression<Action> e) { }
static void CallToAction(Action a) { }
static void CallToExprAc(Expression<Action> a) { }
static void Main(string[] args)
{
// Works
CallToAction(() => Overloaded(() => { int i = 5; }, "hi"));
// Doesn't work - using the Expression overload
CallToAction(() => Overloaded(() => { int i = 5; }));
// Doesn't work - wrapped in an outer Expression
CallToExprAc(() => Overloaded(() => { int i = 5; }, "hi"));
}
Работает ли ваша "поместить лямбда-выражение с выражением в локальный", зависит от того, как реализован FakeItEasy. Я подозреваю, что это сработает здесь, но что-то похожее, например, в LINQ-to-SQL, не сработает - просто произойдет сбой во время выполнения, а не во время компиляции.
Я не уверен, является ли это ошибкой компилятора, ошибкой спецификации или желательным поведением. В разделе 6.5 спецификации C# мы имеем
Определенные лямбда-выражения не могут быть преобразованы в типы дерева выражений: даже если преобразование существует, оно не выполняется во время компиляции. Это тот случай, если лямбда-выражение:
• имеет корпус блока
• Содержит простые или составные операторы присваивания
• Содержит динамически связанное выражение
• асинхронный
который не говорит "содержит лямбда-выражение, которое не может быть преобразовано в тип дерева выражений".