代码之家  ›  专栏  ›  技术社区  ›  MojoFilter

委托关键字与lambda表示法

  •  169
  • MojoFilter  · 技术社区  · 16 年前

    编译后,是否存在以下差异:

    delegate { x = 0; }
    

    () => { x = 0 }
    

    ?

    6 回复  |  直到 7 年前
        1
  •  133
  •   Amy B    10 年前

    简短回答:不。

    可能不相关的较长回答:

    • 如果将lambda分配给委托类型(例如 Func Action )你会得到一个匿名的代表。
    • 如果将lambda赋给表达式类型,将得到表达式树而不是匿名委托。然后可以将表达式树编译为匿名委托。

    编辑: 下面是一些表达式链接。

        2
  •  119
  •   Jon Skeet    8 年前

    我喜欢大卫的回答,但我认为我会学究。这个问题说,“一旦它被编译”,这意味着两个表达式 已编译。它们是如何编译的,但是其中一个被转换为委托,另一个被转换为表达式树?这是一个棘手的问题——您必须使用匿名方法的另一个特性,这是lambda表达式不共享的唯一特性。如果在不指定参数列表的情况下指定匿名方法 完全 它与返回void且没有任何 out 参数。有了这些知识,我们应该能够构造两个重载,使表达式完全不含糊,但非常不同。

    但灾难来袭!至少在C 3.0中,不能将带有块体的lambda表达式转换为表达式-也不能将带有赋值的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; } );
        }
    }
    

    哎哟。记住孩子们,每当您重载从基类继承的方法时,一只小猫咪就会开始哭。

        3
  •  2
  •   Daniel Plaisted    16 年前

    大卫B是对的。注意,使用表达式树可能有好处。Linq to SQL将检查表达式树并将其转换为SQL。

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

        4
  •  2
  •   Matthew    8 年前

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

    表达式:

    () => { x = 0 }
    

    是具有语句体的lambda表达式,因此无法将其编译为表达式树。实际上,它甚至不编译,因为它需要在0之后使用分号:

    () => { x = 0; } // Lambda statement body
    () => x = 0      // Lambda expression body, could be an expression tree. 
    
        5
  •  -1
  •   nawfal Donny V.    11 年前

    有一点不同

    例子:

    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));
    });
    
        6
  •  -2
  •   RBT    7 年前

    这里有一些基本的。

    这是匿名方法

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