Подтвердить что ты не робот

В чем разница между новым действием() и лямбдой?

Итак, когда я пишу что-то вроде этого

Action action = new Action(()=>_myMessage = "hello");

Refactor Pro! Выделяет это как избыточное создание делегата и позволяет мне сократить его до

Action action = () => _myMessage="hello";

И это обычно отлично работает. Обычно, но не всегда. Например, Rhino Mocks имеет метод расширения с именем Do:

IMethodOptions<T> Do(Delegate action);

Здесь прохождение в первой версии работает, а второе - нет. Что именно происходит здесь под обложками?

4b9b3361

Ответ 1

Первая версия эффективно выполняет:

Action tmp = () => _myMessage = "hello";
var action = new Action(tmp);

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

var action = () => _myMessage="hello";

на самом деле не компилируется - это может быть любой тип делегата без каких-либо параметров, и ни одно возвращаемое значение или тот же тип возврата, что и _myMessage (который предположительно string). Например, все они действительны:

Action action = () => _myMessage="hello";
Func<string> action = () => _myMessage="hello";
MethodInvoker action = () => _myMessage="hello";
Expression<Action> = () => _myMessage="hello";
// etc

Как мог компилятор С# определить, какой тип action должен был быть, если он был объявлен с помощью var?

Самый простой способ обойти это при вызове метода (для вашего примера Rhino Mocks) - это сделать:

methodOptions.Do((Action) (() => _myMessage = "hello"));

Ответ 2

Вы подтвердили, что вторая строка действительно компилируется? Он не должен компилироваться, потому что С# не поддерживает назначение лямбда-выражения неявно типизированной переменной (CS0815). Эта строка будет работать в VB.Net, хотя она поддерживает анонимное создание делегата (начиная с VB 9.0).

Версия Rhino Mocks не компилируется по той же причине, что и вторая строка не должна компилироваться. С# не будет автоматически выводить тип выражения лямбда. Лямбда-выражения должны использоваться в контексте, где можно определить тип делегата, который они должны выполнить. Первая строка отлично работает, потому что предполагаемый тип ясен: Action. Версия Rhino Mocks не работает, потому что делегат более сродни абстрактному типу делегатов. Это должен быть конкретный тип делегата, такой как Action или Func.

Для подробного обсуждения этой темы вы должны прочитать записи блога Eric Lippert по теме: http://blogs.msdn.com/ericlippert/archive/2007/01/11/lambda-expressions-vs-anonymous-methods-part-two.aspx