ключевое слово делегирования vs.лямбда-нотация
-
08-07-2019 - |
Вопрос
После компиляции есть ли разница между:
delegate { x = 0; }
и
() => { x = 0 }
?
Решение
Короткий ответ :нет.
Более длинный ответ, который может быть неактуален:
- Если вы назначаете лямбду типу делегата (например,
Func
илиAction
) вы получите анонимного делегата. - Если вы присвоите лямбду типу выражения, вы получите дерево выражений вместо анонимного делегата.Затем дерево выражений можно скомпилировать в анонимный делегат.
Редактировать:Вот несколько ссылок на выражения.
- System.Linq.Expression.Expression(TDelegate) (Начни здесь).
- Linq в памяти с делегатами (например, System.Func) использует System.Linq.Enumerable.Linq to SQL (и все остальное) с выражениями использует System.Linq.Queryable.Проверьте параметры этих методов.
- Ан Объяснение от ScottGu.Короче говоря, Linq в памяти создаст несколько анонимных методов для решения вашего запроса.Linq to SQL создаст дерево выражений, представляющее запрос, а затем преобразует это дерево в T-SQL.Linq to Entities создаст дерево выражений, представляющее запрос, а затем преобразует это дерево в соответствующий платформе SQL.
Другие советы
Мне нравится ответ Дэвида, но я думал, что буду педантичен.В вопросе говорится: «Как только он будет скомпилирован», что предполагает, что оба выражения иметь был составлен.Как они могли скомпилироваться, но один из них был преобразован в делегат, а другой в дерево выражений?Это непростая задача — вам придется использовать еще одну особенность анонимных методов;единственный, который не используется лямбда-выражениями.Если вы укажете анонимный метод без указания списка параметров совсем он совместим с любым типом делегата, возвращающим void и без каких-либо out
параметры.Вооружившись этими знаниями, мы сможем построить две перегрузки, чтобы сделать выражения совершенно однозначными, но очень разными.
Но случается беда!По крайней мере, в C# 3.0 вы не можете преобразовать лямбда-выражение с телом блока в выражение, а также не можете преобразовать лямбда-выражение с присваиванием в теле (даже если оно используется в качестве возвращаемого значения).Это может измениться с выходом C# 4.0 и .NET 4.0, которые позволяют больше выражать в дереве выражений.Другими словами, с примерами, которые привел MojoFilter, эти двое будут почти всегда конвертироваться в одно и то же.(Подробнее через минуту.)
Мы можем использовать трюк с параметрами делегата, если немного изменим тела:
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; } );
}
}
Ой.Помните, дети, каждый раз, когда вы перегружаете метод, унаследованный от базового класса, маленький котенок начинает плакать.
Дэвид Б. прав.Обратите внимание, что использование деревьев выражений может иметь преимущества.LINQ to SQL проверит дерево выражений и преобразует его в SQL.
Вы также можете поэкспериментировать с лямбдами и деревьями выражений, чтобы эффективно передавать имена членов класса в структуру безопасным для рефакторинга способом. Мокк является примером этого.
В двух приведенных выше примерах разницы нет, ноль.
Выражение:
() => { x = 0 }
— это лямбда-выражение с телом инструкции, поэтому его нельзя скомпилировать как дерево выражений.На самом деле он даже не компилируется, потому что после 0 нужна точка с запятой:
() => { x = 0; } // Lambda statement body
() => x = 0 // Lambda expression body, could be an expression tree.
Есть разница
Пример:
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));
});
Некоторые основы здесь.
Это анонимный метод
(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);