Ошибка компилятора для выражений / перегруженных функций

Скриншот говорит об этом в значительной степени. У меня есть перегрузки, как видно на скриншоте. При использовании строки в качестве второго параметра компилятор должен выяснить, что первый аргумент может быть только Func, а не выражением. Но компилятор выдает ошибку, говоря: "Выражение lamda с телом оператора не может быть преобразовано в дерево выражений".

Почему компилятор не может определить правильную перегрузку?

Явное приведение не помогает. Что работает, когда я делаю локальную переменную типа Func, а затем использую это вместо.

Используемая среда - FakeItEasy 1.24.0.

WTF

РЕДАКТИРОВАТЬ:

Вот код, который показывает поведение:

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# мы имеем

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

• имеет корпус блока

• Содержит простые или составные операторы присваивания

• Содержит динамически связанное выражение

• асинхронный

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

Другие вопросы по тегам