188

编译后,两者之间是否有区别:

delegate { x = 0; }

() => { x = 0 }

?

4

6 回答 6

142

简短的回答:没有。

可能不相关的更长答案:

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

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

  • System.Linq.Expression.Expression(TDelegate)(从这里开始)。
  • 带有委托(例如 System.Func)的 Linq in-memory 使用System.Linq.Enumerable。带有表达式的 Linq to SQL(以及其他任何东西)使用System.Linq.Queryable。查看这些方法的参数。
  • ScottGu的解释。简而言之,Linq in-memory 会产生一些匿名方法来解决您的查询。Linq to SQL 将生成一个表示查询的表达式树,然后将该树转换为 T-SQL。Linq to Entities 将生成一个表示查询的表达式树,然后将该树转换为适合平台的 SQL。
于 2008-11-18T18:43:35.810 回答
126

我喜欢艾米的回答,但我认为我会很迂腐。问题是“一旦编译” - 这表明两个表达式都已编译。它们怎么能同时编译,但一个被转换为委托,一个被转换为表达式树?这是一个棘手的问题——你必须使用匿名方法的另一个特性;唯一不被 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; } );
    }
}

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

于 2008-11-18T19:32:28.877 回答
2

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

表达方式:

() => { x = 0 }

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

() => { x = 0; } // Lambda statement body
() => x = 0      // Lambda expression body, could be an expression tree. 
于 2008-11-18T18:55:28.750 回答
2

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

您还可以使用 lamdas 和表达式树来有效地将类成员的名称以重构安全的方式传递给框架。 起订量就是一个例子。

于 2008-11-18T18:59:25.263 回答
-1

它们是有区别的

例子:

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

我用 lambda:(error) 替换

var mytask = Task.Factory.StartNew(() =>
{
    Thread.Sleep(5000);
    return 2712;
});
mytask.ContinueWith(()=>
{
    _backgroundTask.ContinueTask(() =>lblPercent.Content = mytask.Result.ToString(CultureInfo.InvariantCulture));
});
于 2012-05-25T01:44:17.263 回答
-1

这里有一些基础知识。

这是一个匿名方法

(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);
于 2018-05-13T07:14:07.003 回答