何时不使用 lambda 表达式 [英] When not to use lambda expressions

查看:24
本文介绍了何时不使用 lambda 表达式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 StackOverflow 上回答了很多问题,成员指定了如何使用 lambda 表达式.

A lot of questions are being answered on Stack Overflow, with members specifying how to solve these real world/time problems using lambda expressions.

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

Are we overusing it, and are we considering the performance impact of using lambda expressions?

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

I found a few articles that explores the performance impact of lambda vs anonymous delegates vs for/foreach loops with different results

  1. 匿名委托 vs Lambda 表达式 vs 函数调用性能
  2. foreach 与 List.ForEach 的性能
  3. .NET/C# 循环性能测试(FOR、FOREACH、LINQ 和 Lambda).
  4. DataTable.Select比LINQ快

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

What should be the evaluation criteria when choosing the appropriate solution? Except for the obvious reason that it's more concise code and readable when using lambda.

推荐答案

尽管我将重点放在第一点,但我首先会在整个性能问题上付出 2 美分.除非差异很大或使用量很大,否则我通常不会担心添加微秒时不会对用户产生任何可见差异.我强调,我只在考虑非密集调用方法时才不在乎.我在设计应用程序本身的方式上确实有特殊的性能考虑.我关心缓存,关心线程的使用,关心调用方法的巧妙方法(无论是进行多次调用还是尝试只进行一次调用),是否将连接池化,等等.实际上我通常不不关注原始性能,而是关注可扩展性.对于单个用户,我不在乎它是否能在一小部分纳秒内运行得更好,但我非常关心能够为系统加载大量同时使用的用户而不会注意到影响.

Even though I will focus on point one, I begin by giving my 2 cents on the whole issue of performance. Unless differences are big or usage is intensive, usually I don't bother about microseconds that when added don't amount to any visible difference to the user. I emphasize that I only don't care when considering non-intensive called methods. Where I do have special performance considerations is on the way I design the application itself. I care about caching, about the use of threads, about clever ways to call methods (whether to make several calls or to try to make only one call), whether to pool connections or not, etc., etc. In fact I usually don't focus on raw performance, but on scalibility. I don't care if it runs better by a tiny slice of a nanosecond for a single user, but I care a lot to have the ability to load the system with big amounts of simultaneous users without noticing the impact.

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

Having said that, here goes my opinion about point 1. I love anonymous methods. They give me great flexibility and code elegance. The other great feature about anonymous methods is that they allow me to directly use local variables from the container method (from a C# perspective, not from an IL perspective, of course). They spare me loads of code oftentimes. When do I use anonymous methods? Evey single time the piece of code I need isn't needed elsewhere. If it is used in two different places, I don't like copy-paste as a reuse technique, so I'll use a plain ol' delegate. So, just like shoosh answered, it isn't good to have code duplication. In theory there are no performance differences as anonyms are C# tricks, not IL stuff.

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

Most of what I think about anonymous methods applies to lambda expressions, as the latter can be used as a compact syntax to represent anonymous methods. Let's assume the following method:

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

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

It receives an array of strings and for each one of them, it will call the method passed to it. If that method returns true, it will say "Found...". You can call this method the following way:

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

但是,您也可以这样称呼它:

But, you can also call it the following way:

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

两者在 IL 方面没有区别,因为使用 Lambda 表达式的那个更具可读性.再一次,没有性能影响,因为这些都是 C# 编译器技巧(不是 JIT 编译器技巧).正如我不觉得我们过度使用匿名方法一样,我也不觉得我们过度使用 Lambda 表达式来表示匿名方法.当然,同样的逻辑适用于重复的代码:不要使用 lambda,使用常规委托.还有其他限制会导致您返回匿名方法或普通委托,例如 out 或 ref 参数传递.

There is no difference in IL between the both, being that the one using the Lambda expression is much more readable. Once again, there is no performance impact as these are all C# compiler tricks (not JIT compiler tricks). Just as I didn't feel we are overusing anonymous methods, I don't feel we are overusing Lambda expressions to represent anonymous methods. Of course, the same logic applies to repeated code: Don't do lambdas, use regular delegates. There are other restrictions leading you back to anonymous methods or plain delegates, like out or ref argument passing.

Lambda 表达式的另一个优点是完全相同的语法不需要表示匿名方法.Lambda 表达式也可以表示……你猜对了,表达式.举个例子:

The other nice things about Lambda expressions is that the exact same syntax doesn't need to represent an anonymous method. Lambda expressions can also represent... you guessed, expressions. Take the following example:

public static void DoSomethingExpression(string[] names, System.Linq.Expressions.Expression<Func<string, bool>> 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());
    }
 }

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

Notice the slightly different signature. The second parameter receives an expression and not a delegate. The way to call this method would be:

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

这与我们在使用 lambda 创建匿名方法时所做的调用完全相同.这里的区别在于我们不是在创建匿名方法,而是创建了一个表达式树.正是由于这些表达式树,我们可以将 lambda 表达式转换为 SQL,这就是 Linq 2 SQL 所做的,例如,而不是在引擎中为每个子句执行诸如 Where、Select 等内容.是因为无论您是创建匿名方法还是发送表达式,调用语法都是相同的.

Which is exactly the same as the call we made when creating an anonymous method with a lambda. The difference here is that we are not creating an anonymous method, but creating an expression tree. It is due to these expression trees that we can then translate lambda expressions to SQL, which is what Linq 2 SQL does, for instance, instead of executing stuff in the engine for each clause like the Where, the Select, etc. The nice thing is that the calling syntax is the same whether you're creating an anonymous method or sending an expression.

这篇关于何时不使用 lambda 表达式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆