当前位置:  开发笔记 > 编程语言 > 正文

何时不使用lambda表达式

如何解决《何时不使用lambda表达式》经验,为你挑选了5个好方法。

Stack Overflow正在回答很多问题,成员们指定如何使用lambda表达式解决这些现实世界/时间问题.

我们是否过度使用它,我们是否在考虑使用lambda表达式对性能的影响?

我发现了一些文章,探讨了lambda与匿名委托vs for/ foreach循环对不同结果的性能影响

    匿名委托与Lambda表达式与函数调用性能

    foreach与List.ForEach的表现

    .NET/C#循环性能测试(FOR,FOREACH,LINQ和Lambda).

    DataTable.Select比LINQ更快

选择合适的解决方案时,评估标准应该是什么?除了明显的原因,它使用lambda时更简洁的代码和可读性.



1> Rui Craveiro..:

即使我将重点放在第一点,我首先在整个性能问题上给出2美分.除非差异很大或者使用密集,否则我通常不会担心添加的微秒不会对用户产生任何明显的差异.我强调在考虑非密集调用方法时我只是不在乎.我在哪里有特殊的性能考虑因素是我设计应用程序本身的方式.我关心缓存,关于线程的使用,关于调用方法的聪明方法(是否进行多次调用或尝试只进行一次调用),是否汇集连接等等.事实上我通常都不喜欢不是关注原始性能,而是关注可扩展性.对于单个用户来说,我不关心它是否会以一小片纳秒的速度运行得更好,但我非常关心能够在没有注意到影响的情况下加载具有大量并发用户的系统.

话虽如此,这里是我对第1点的看法.我喜欢匿名方法.它们给了我极大的灵活性和代码优雅.匿名方法的另一个重要特性是它们允许我直接使用容器方法中的局部变量(从C#角度来看,当然不是从IL角度来看).他们经常为我提供大量代码.我什么时候使用匿名方法?Evey单一时间我需要的代码片段在其他地方不需要.如果它在两个不同的地方使用,我不喜欢复制粘贴作为重用技术,所以我将使用普通的'委托'.所以,就像shoosh回答的那样,重复代码并不好.理论上没有性能差异,因为anonyms是C#技巧,而不是IL的东西.

我对匿名方法的大部分内容都适用于lambda表达式,因为后者可以用作表示匿名方法的紧凑语法.我们假设以下方法:

public static void DoSomethingMethod(string[] names, Func myExpression)
{
    Console.WriteLine("Lambda used to represent an anonymous method");
    foreach (var item in names)
    {
        if (myExpression(item))
            Console.WriteLine("Found {0}", item);
    }
}

它接收一个字符串数组,对于每个字符串,它将调用传递给它的方法.如果该方法返回true,则会显示"Found ...".您可以通过以下方式调用此方法:

string[] names = {"Alice", "Bob", "Charles"};
DoSomethingMethod(names, delegate(string p) { return p == "Alice"; });

但是,您也可以通过以下方式调用它:

DoSomethingMethod(names, p => p == "Alice");

IL之间没有差别,因为使用Lambda表达式的IL更易读.再一次,没有性能影响,因为这些都是C#编译器技巧(不是JIT编译器技巧).就像我不认为我们过度使用匿名方法一样,我不认为我们过度使用Lambda表达式来表示匿名方法.当然,相同的逻辑适用于重复的代码:不要做lambdas,使用常规委托.还有其他限制会导致您回到匿名方法或普通代理,例如out或ref参数传递.

Lambda表达式的其他好处是完全相同的语法不需要表示匿名方法.Lambda表达式也可以表示......你猜对了,表达式.请看以下示例:

public static void DoSomethingExpression(string[] names, System.Linq.Expressions.Expression> myExpression)
{
    Console.WriteLine("Lambda used to represent an expression");
    BinaryExpression bExpr = myExpression.Body as BinaryExpression;
    if (bExpr == null)
        return;
    Console.WriteLine("It is a binary expression");
    Console.WriteLine("The node type is {0}", bExpr.NodeType.ToString());
    Console.WriteLine("The left side is {0}", bExpr.Left.NodeType.ToString());
    Console.WriteLine("The right side is {0}", bExpr.Right.NodeType.ToString());
    if (bExpr.Right.NodeType == ExpressionType.Constant)
    {
        ConstantExpression right = (ConstantExpression)bExpr.Right;
        Console.WriteLine("The value of the right side is {0}", right.Value.ToString());
    }
 }

请注意略有不同的签名.第二个参数接收表达式而不是委托.调用此方法的方法是:

DoSomethingExpression(names, p => p == "Alice");

这与我们使用lambda创建匿名方法时的调用完全相同.这里的不同之处在于我们不是创建匿名方法,而是创建表达式树.正是由于这些表达式树,我们才能将lambda表达式转换为SQL,这就是Linq 2 SQL所做的,而不是在引擎中为Where,Select等等每个子句执行东西.无论您是创建匿名方法还是发送表达式,调用语法都是相同的.


+1所有好东西.一个小的修正:实例化调用和GC-an匿名方法的开销是以纳秒为单位,而不是微秒!

2> Jerry Nixon..:

我的答案不会受欢迎.

我相信Lambda的99%总是更好的选择,原因有三个.

首先,假设您的开发人员很聪明,绝对没有错.其他答案有一个潜在的前提,即每个开发人员,但你是愚蠢的.不是这样.

其次,Lamdas(等)是一种现代语法 - 明天它们将比现在更常见.您的项目代码应该来自当前和新兴的约定.

第三,编写代码"老式的方式"对你来说似乎更容易,但对编译器来说并不容易.这很重要,随着编译器的重新编译,遗留方法几乎没有机会得到改进.Lambdas(等)依靠编译器来扩展它们可以受益,因为编译器随着时间的推移更好地处理它们.

总结一下:

    开发人员可以处理它

    每个人都这样做

    有未来的潜力

我再次知道这不是一个受欢迎的答案.相信我"简单就是最好"也是我的口头禅.维护是任何来源的重要方面.我知道了.但我认为我们用一些陈词滥调的经验法则掩盖了现实.

// 杰瑞


这个答案唯一不对的是第一句中的错误:)
这个答案有两个问题,一个是你没有回答这个问题,问题是1%.二,你马上开始"更好",但比什么更好?如果你的意思是与`delegate`关键字比较,我同意.如果你的意思比编写命名方法更好,那么我不同意
我无法相信我没有提到减少代码行数会增加源代码的可读性.我可以比27,000更容易吸收2,700行.Lambdas有助于减少代码行数.

3> shoosh..:

代码重复.
如果您发现自己不止一次编写相同的匿名函数,则不应该是一个.



4> Marc Gravell..:

好吧,当我们讨论委托使用时,lambda和匿名方法之间应该没有任何区别 - 它们是相同的,只是语法不同.从运行时的角度来看,命名方法(用作委托)也​​是相同的.然后,区别在于使用委托与内联代码 - 即

list.ForEach(s=>s.Foo());
// vs.
foreach(var s in list) { s.Foo(); }

(我希望后者更快)

而同样的,如果你是在谈论什么其他比在内存中的对象,lambda表达式是保持类型检查(而不是解析字符串所有的时间)的条款你最有力的工具之一.

当然,有些情况下,简单foreach的代码将比LINQ版本更快,因为调用的次数会减少,并且调用会花费很少但可测量的时间.但是,在许多情况下,代码根本不是瓶颈,而更简单的代码(特别是对于分组等)的价值远远超过几纳秒.

另请注意,在.NET 4.0中,还有其他Expression节点,例如循环,逗号等.语言不支持它们,但运行时支持它们.我只是为了完整性而提到这一点:我当然不是说你应该Expression在哪里使用手工构造foreach!


古老的skool anon的一个小优势.方法是,如果你对它们不感兴趣,你可以省略参数声明,而lambdas需要声明正确数量的args.button.Click + = delegate {Foo(); }; vs. button.Click + =(sender,event)=> Foo();
具有讽刺意味的是,事实并非如此.信不信由你,List.ForEach有优势.单个委托的调用非常快(接近与接口调用相同的速度).

5> Razzie..:

我会说性能差异通常很小(在循环的情况下,显然,如果你看看第二篇文章的结果(顺便说一句,Jon Skeet 在这里有类似的文章)),你几乎不应该选择仅出于性能原因的解决方案,除非您正在编写一个软件,其中性能绝对最重要的非功能性要求,并且您必须进行微优化.

什么时候选择?我想这取决于情况,但也取决于人.举个例子,有些人在普通的foreach循环中使用List.Foreach.我个人更喜欢后者,因为它通常更具可读性,但我可以与谁争论呢?

推荐阅读
和谐啄木鸟
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有