delegate 关键字与 lambda 表示法

发布于 2024-07-09 06:00:18 字数 129 浏览 12 评论 0原文

编译后,:

delegate { x = 0; }

() => { x = 0 }

之间有区别吗?

Once it is compiled, is there a difference between:

delegate { x = 0; }

and

() => { x = 0 }

?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

心碎的声音 2024-07-16 06:00:18

简短的回答:不。

更长的答案可能不相关:

  • 如果将 lambda 分配给委托类型(例如 FuncAction),您将获得一个匿名委托。
  • 如果将 lambda 分配给表达式类型,您将获得表达式树而不是匿名委托。 然后可以将表达式树编译为匿名委托。

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

Short answer : no.

Longer answer that may not be relevant:

  • If you assign the lambda to a delegate type (such as Func or 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.

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.
半山落雨半山空 2024-07-16 06:00:18

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

但灾难降临了! 至少在 C# 3.0 中,您无法将带有块主体的 lambda 表达式转换为表达式 - 也无法将带有主体中赋值的 lambda 表达式转换为(即使它用作返回值)。 这可能会随着 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; } );
    }
}

哎呀。 孩子们,请记住,每次重载从基类继承的方法时,就会有一只小猫开始哭泣。

I like Amy's answer, but I thought I'd be pedantic. The question says, "Once it is compiled" - which suggests that both expressions have been 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 all it is compatible with any delegate type returning void and without any out parameters. Armed with this knowledge, we should be able to construct two overloads to make the expressions completely unambiguous but very different.

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 almost always be converted to the same thing. (More details in a minute.)

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.

且行且努力 2024-07-16 06:00:18

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

表达式:

() => { x = 0 }

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

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

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:

() => { x = 0; } // Lambda statement body
() => x = 0      // Lambda expression body, could be an expression tree. 
指尖上的星空 2024-07-16 06:00:18

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

您还可以使用 lamda 和表达式树来以重构安全的方式有效地将类成员的名称传递到框架。 Moq 就是一个示例。

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.

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. Moq is an example of this.

蔚蓝源自深海 2024-07-16 06:00:18

有区别

示例:

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

我用 lambda 替换:(错误)

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

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)

var mytask = Task.Factory.StartNew(() =>
{
    Thread.Sleep(5000);
    return 2712;
});
mytask.ContinueWith(()=>
{
    _backgroundTask.ContinueTask(() =>lblPercent.Content = mytask.Result.ToString(CultureInfo.InvariantCulture));
});
清君侧 2024-07-16 06:00:18

这里有一些基础知识。

这是一个匿名方法

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

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

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

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

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

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

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

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

We can use a func delegate to use this expression.

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

bool result = checkStudentAge ( Student Object);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文