2012-04-17 2 views
22

Есть ли способ выполнить лямбда-выражение сразу после его определения?Выполнить лямбда-выражение сразу после его определения?

Другими словами (Invalid C# код):

(() => { Console.WriteLine("Hello World"); }).Invoke(); 
+0

Подождите ... что? Почему это лямбда-выражение? – scottheckel

+4

Причина, по которой ваш код недействителен, заключается в том, что вы не сказали компилятору, хотите ли вы «Действие» или «Выражение ». Если вы произнесете это лямбда-выражение в «Действие», вы сможете вызвать 'Invoke' на нем или использовать синтаксис метода-вызова'() 'для его вызова. – phoog

+4

Мое воображение, возможно, сбивает меня, есть ли настоящая необходимость сделать это? –

ответ

32

Sure.

new Action(() => { Console.WriteLine("Hello World"); })(); 

Это должно сделать трюк.

3

Вы должны быть в состоянии сделать это:

Action runMe =() => { Console.WriteLine("Hello World"); }; 
runMe(); 
+0

Исправить. Компилятор интерпретирует синтаксис лямбда как сокращение для делегата. Это только если вы назначаете в тип 'Expression ', что он будет строить дерево выражений. – Tejs

+3

Это не скомпилируется, потому что компилятор не может понять, хотите ли вы «Action» или «Expression ». – phoog

+1

@phoog правильный. Это не скомпилируется. «Невозможно назначить лямбда-выражение для неявно типизированной локальной переменной." –

12

Другой «вариант», который находится всего в двух других ответов в несколько измененном виде:

((Action)(() => { Console.WriteLine("Hello World"); }))(); 

Причина, , как непосредственно взято из комментария phoog:

... вы не сказали компилятору, r вы хотите Action или Expression<Action>. Если вы листинг, то выражение lambda на Action, вы сможете вызвать Invoke на нем или использовать синтаксис метода-вызова() для его вызова.

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

+0

Вы полностью можете сделать рекурсию с помощью Y combinator:' public delegate T Recursive (Рекурсивный f, T n); static void Main (string [] args) {System.Console. WriteLine («Factorial 5 = {0}», новый рекурсивный ((f, n) => f (f, n)) (новый рекурсивный ((f, n) => (n == 0)? 1: n * f (f, n - 1)), 5));} '. Это хак из чисто функционального мира, который в основном объявляет функцию' f', беря себя за параметр и рекурсивно называя себя, передавая f '. Чтобы запустить рекурсию, эта функция передается другой, которая вызывает' f' с 'f' и начальное значение параметра. –

1

Вот пример того, как это могут быть использованы. Вы хотите инициализировать конструктор с результатом нескольких строк кода, которые не могут быть записаны как функция, потому что так структурируется сторонний API.

Это всего лишь код клея, чтобы предотвратить запись автономной функции, которая никогда не называется нигде. Я использую Func вместо Action, но ответ такой же, как у пользователя166390.

 // imagine several dozens of lines that look like this 
     // where the result is the return value of a function call 
     fields.Add(new ProbeField(){ 
      Command = "A", 
      Field = "Average", 
      Value = be.GetAverage() 
     }); 

     // now you need something that can't be expressed as function call 
     // so you wrap it in a lambda and immediately call it. 
     fields.Add(new ProbeField(){ 
      Command = "C", 
      Field = "Cal Coeff", 
      Value = ((Func<string>)(() => { 
       CalCoef coef; 
       Param param; 
       be.GetCalibrationCoefficients(out coef, out param); 
       return coef.lowDet1.ToString(); 
      }))() 
     });