2015-01-12 2 views
7

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

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

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

Рамки используется FakeItEasy 1.24.0

Wtf?

EDIT:

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

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(); 
    } 
+4

не могли бы вы опубликовать код, а не скриншот? – mybirthname

+2

Вы не используете 'return' только для тела лямбда только для выражения ....' string => true'. – leppie

+1

@leppie: правильно, но это не так. Как вы можете видеть на скриншоте, компилятор должен использовать перегрузку с помощью Func , и поэтому тело метода должно быть в порядке. Вместо этого компилятор дает ошибку. Вопрос в том, почему. – cmart

ответ

6

вопрос не находится в вызов 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# мы имеем

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

• Имеет блок тело

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

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

• Является ли асинхронной

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

+0

Ах .. Хорошая мысль! И да, он также работает во время выполнения, когда вы создаете локальную переменную. Thx! – cmart

+0

@MarChr Рад это услышать, и хорошее место - безусловно, интересная проблема. – Rawling

+0

Да, но это также имеет смысл. Спасибо! – cmart

Смежные вопросы