C# 委托关键字与 lambda 符号

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/299703/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 22:14:53  来源:igfitidea点击:

delegate keyword vs. lambda notation

c#.netdelegateslambdaanonymous-methods

提问by MojoFilter

Once it is compiled, is there a difference between:

编译后,是否有区别:

delegate { x = 0; }

and

() => { x = 0 }

?

?

采纳答案by Amy B

Short answer : no.

简短的回答:没有。

Longer answer that may not be relevant:

可能不相关的更长答案:

  • If you assign the lambda to a delegate type (such as Funcor Action) you'll get an anonymous delegate.
  • If you assign the lambda to an Expression type, you'll get an expression tree instead of a anonymous delegate. The expression tree can then be compiled to an anonymous delegate.
  • 如果您将 lambda 分配给委托类型(例如FuncAction),您将获得一个匿名委托。
  • 如果您将 lambda 分配给 Expression 类型,您将获得一个表达式树而不是匿名委托。然后可以将表达式树编译为匿名委托。

Edit: Here's some links for Expressions.

编辑:这是表达式的一些链接。

  • System.Linq.Expression.Expression(TDelegate)(start here).
  • Linq in-memory with delegates (such as System.Func) uses System.Linq.Enumerable. Linq to SQL (and anything else) with expressions uses System.Linq.Queryable. Check out the parameters on those methods.
  • An Explanation from ScottGu. In a nutshell, Linq in-memory will produce some anonymous methods to resolve your query. Linq to SQL will produce an expression tree that represents the query and then translate that tree into T-SQL. Linq to Entities will produce an expression tree that represents the query and then translate that tree into platform appropriate SQL.
  • 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。

回答by Olmo

In the two examples above there's no difference, zero.

在上面的两个示例中,没有区别,为零。

The expression:

表达方式:

() => { x = 0 }

is a Lambda expression with statement body, so it can't be compiled as an expression tree. In fact it doesn't even compile because it needs a semicolon after 0:

是带有语句体的 Lambda 表达式,因此不能编译为表达式树。事实上,它甚至无法编译,因为它需要在 0 后加一个分号:

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

回答by Daniel Plaisted

Amy B is correct. Note that there can be advantages to using expression trees. LINQ to SQL will examine the expression tree and convert it to SQL.

艾米 B 是正确的。请注意,使用表达式树可能有优势。LINQ to SQL 将检查表达式树并将其转换为 SQL。

You can also play tricks with lamdas and expression trees to effectively pass the names of class members to a framework in a refactoring-safe way. Moqis an example of this.

您还可以玩弄 lamda 和表达式树的技巧,以重构安全的方式有效地将类成员的名称传递给框架。 Moq就是一个例子。

回答by Jon Skeet

I like Amy's answer, but I thought I'd be pedantic. The question says, "Once it is compiled" - which suggests that both expressions havebeen compiled. How could they both compile, but with one being converted to a delegate and one to an expression tree? It's a tricky one - you have to use another feature of anonymous methods; the only one which isn't shared by lambda expressions. If you specify an anonymous method without specifying a parameter list at allit is compatible with any delegate type returning void and without any outparameters. Armed with this knowledge, we should be able to construct two overloads to make the expressions completely unambiguous but very different.

我喜欢艾米的回答,但我想我会迂腐。问题说,“一旦编译” - 这表明两个表达式都已编译。它们如何编译,但一个被转换为委托,一个被转换为表达式树?这是一个棘手的问题——你必须使用匿名方法的另一个特性;lambda 表达式不共享的唯一一个。如果您指定匿名方法而根本不指定参数列表则它与返回 void 且不带任何out参数的任何委托类型兼容。有了这些知识,我们应该能够构造两个重载,使表达式完全明确但又非常不同。

But disaster strikes! At least with C# 3.0, you can't convert a lambda expression with a block body into an expression - nor can you convert a lambda expression with an assignment in the body (even if it is used as the return value). This may change with C# 4.0 and .NET 4.0, which allow more to be expressed in an expression tree. So in other words, with the examples MojoFilter happened to give, the two will almostalways be converted to the same thing. (More details in a minute.)

但是灾难来了!至少在 C# 3.0 中,您不能将带有块体的 lambda 表达式转换为表达式 - 也不能将带有赋值的 lambda 表达式在体中转换(即使它被用作返回值)。这可能会随着 C# 4.0 和 .NET 4.0 发生变化,允许在表达式树中表达更多内容。所以换句话说,使用 MojoFilter 碰巧给出的例子,两者几乎总是会被转换为相同的东西。(一分钟了解更多细节。)

We can use the delegate parameters trick if we change the bodies a little bit though:

如果我们稍微改变主体,我们可以使用委托参数技巧:

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...");
    }
}

But wait! We can differentiate between the two even without using expression trees, if we're cunning enough. The example below uses the overload resolution rules (and the anonymous delegate matching trick)...

可是等等!如果我们足够狡猾,即使不使用表达式树,我们也可以区分两者。下面的示例使用重载解析规则(和匿名委托匹配技巧)...

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; } );
    }
}

Ouch. Remember kids, every time you overload a method inherited from a base class, a little kitten starts crying.

哎哟。记住孩子们,每次重载从基类继承的方法时,小猫都会开始哭泣。

回答by án Bình Tr?ng

There is a difference

它们是有区别的

Example:

例子:

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

And I replace with lambda:(error)

我用 lambda 替换:(错误)

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

回答by Yogesh Prajapati

Some basics here.

这里有一些基础知识。

This is a anonymous method

这是一个匿名方法

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

As anonymous methods do not have names we need a delegate in which we can assign both of these methods or expressions. e.g.

由于匿名方法没有名称,我们需要一个委托,我们可以在其中分配这两个方法或表达式。例如

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

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


Same with the lambda expression. Usually we need a delegate to use them

与 lambda 表达式相同。通常我们需要一个委托来使用它们

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

We can use a func delegate to use this expression.

我们可以使用 func 委托来使用这个表达式。

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

bool result = checkStudentAge ( Student Object);