Ключевое слово delegate или lambda

Как только он скомпилирован, существует ли разница между:

delegate { x = 0; }

и

() => { x = 0 }

?

Ответ 1

Короткий ответ: нет.

Более длинный ответ, который может быть неактуальным:

  • Если вы назначаете lambda для типа делегата (например, Func или Action), вы получите анонимный делегат.
  • Если вы назначаете lambda для типа Expression, вы получите дерево выражений вместо анонимного делегата. Затем дерево выражений можно скомпилировать анонимному делегату.

Изменить: Вот некоторые ссылки для выражений.

  • System.Linq.Expression.Expression(TDelegate) (начало здесь).
  • Linq в памяти с делегатами (например, System.Func) использует System.Linq.Enumerable. Linq to SQL (и все остальное) с выражениями использует System.Linq.Queryable. Проверьте параметры этих методов.
  • Объяснение из ScottGu. В двух словах, Linq in-memory создаст некоторые анонимные методы для решения вашего запроса. Linq to SQL создает дерево выражений, которое представляет запрос, а затем переводит это дерево в T-SQL. Linq to Entities будет генерировать дерево выражений, которое представляет запрос, а затем перевести это дерево в подходящий SQL-сервер.

Ответ 2

Мне нравится Дэвид, но я думал, что буду педантичным. В этом вопросе говорится: "Как только он скомпилирован" - это говорит о том, что оба выражения были скомпилированы. Как они могут скомпилировать, но с одним преобразованным в делегат, а другой - в дерево выражений? Это сложная задача - вам нужно использовать другую функцию анонимных методов; единственный, который не разделяется лямбда-выражениями. Если вы укажете анонимный метод без указания списка параметров, он будет совместим с любым типом делегата, возвращающим void и без каких-либо параметров out. Вооружившись этими знаниями, мы должны иметь возможность построить две перегрузки, чтобы сделать выражения совершенно однозначными, но очень разными.

Но удары бедствия! По крайней мере, с С# 3.0 вы не можете преобразовать лямбда-выражение с блочным телом в выражение - и вы не можете преобразовать лямбда-выражение с назначением в тело (даже если оно используется как возвращаемое значение). Это может измениться с помощью С# 4.0 и .NET 4.0, которые позволяют больше выражать в дереве выражений. Таким образом, другими словами, с примерами, которые МоджоФилтер дал, они почти всегда будут преобразованы в одно и то же. (Подробнее в минуту.)

Мы можем использовать трюк параметров делегата, если немного изменить тела:

using System;
using System.Linq.Expressions;

public class Test
{
    static void Main()
    {
        int x = 0;
        Foo( () => x );
        Foo( delegate { return x; } );
    }

    static void Foo(Func<int, int> action)
    {
        Console.WriteLine("I suspect the anonymous method...");
    }

    static void Foo(Expression<Func<int>> func)
    {
        Console.WriteLine("I suspect the lambda expression...");
    }
}

Но подождите! Мы можем различать два даже без использования деревьев выражений, если мы достаточно хитры. В приведенном ниже примере используются правила разрешения перегрузки (и трюк с анонимным делегатом)...

using System;
using System.Linq.Expressions;

public class Base
{
    public void Foo(Action action)
    {
        Console.WriteLine("I suspect the lambda expression...");
    }
}

public class Derived : Base
{
    public void Foo(Action<int> action)
    {
        Console.WriteLine("I suspect the anonymous method...");
    }
}

class Test
{
    static void Main()
    {
        Derived d = new Derived();
        int x = 0;
        d.Foo( () => { x = 0; } );
        d.Foo( delegate { x = 0; } );
    }
}

Уч. Помните детей, каждый раз, когда вы перегружаете метод, унаследованный от базового класса, маленький котенок начинает плакать.

Ответ 3

В двух приведенных выше примерах нет разницы, ноль.

Выражение:

() => { x = 0 }

- это выражение Lambda с телом оператора, поэтому оно не может быть скомпилировано как дерево выражений. На самом деле он даже не компилируется, потому что ему нужна точка с запятой после 0:

() => { x = 0; } // Lambda statement body
() => x = 0      // Lambda expression body, could be an expression tree. 

Ответ 4

Эми Б правильно. Обратите внимание, что могут быть преимущества использования деревьев выражений. LINQ to SQL проверит дерево выражений и преобразует его в SQL.

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

Ответ 5

Есть разница

Пример:

var mytask = Task.Factory.StartNew(() =>
{
    Thread.Sleep(5000);
    return 2712;
});
mytask.ContinueWith(delegate
{
    _backgroundTask.ContinueTask(() =>lblPercent.Content = mytask.Result.ToString(CultureInfo.InvariantCulture));
});   

И я заменяю лямбдой: (ошибка)

var mytask = Task.Factory.StartNew(() =>
{
    Thread.Sleep(5000);
    return 2712;
});
mytask.ContinueWith(()=>
{
    _backgroundTask.ContinueTask(() =>lblPercent.Content = mytask.Result.ToString(CultureInfo.InvariantCulture));
});

Ответ 6

Некоторые основы здесь.

Это анонимный метод

(string testString) => { Console.WriteLine(testString); };

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

delegate void PrintTestString(string testString); // declare a delegate

PrintTestString print = (string testString) => { Console.WriteLine(testString); }; 
print();

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

s => s.Age > someValue && s.Age < someValue    // will return true/false

Мы можем использовать делегат func для использования этого выражения.

Func< Student,bool> checkStudentAge = s => s.Age > someValue && s.Age < someValue ;

bool result = checkStudentAge ( Student Object);