C# 何时不使用 lambda 表达式

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/672918/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 12:48:20  来源:igfitidea点击:

When not to use lambda expressions

c#.netlambdaanonymous-methods

提问by Binoj Antony

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

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

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

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

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

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

  1. Anonymous Delegates vs Lambda Expressions vs Function Calls Performance
  2. Performance of foreach vs. List.ForEach
  3. .NET/C# Loop Performance Test (FOR, FOREACH, LINQ, & Lambda).
  4. DataTable.Select is faster than LINQ
  1. 匿名委托 vs Lambda 表达式 vs 函数调用性能
  2. foreach 与 List.ForEach 的性能
  3. .NET/C# 循环性能测试(FOR、FOREACH、LINQ 和 Lambda)
  4. DataTable.Select 比 LINQ 快

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.

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

回答by shoosh

Code duplication.
If you find yourself writing the same anonymous function more than once, it shouldn't be one.

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

回答by Marc Gravell

Well, when we are talking bout delegate usage, there shouldn't be any difference between lambda and anonymous methods -- they are the same, just with different syntax. And named methods (used as delegates) are also identical from the runtime's viewpoint. The difference, then, is between using delegates, vs. inline code - i.e.

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

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

(where I would expect the latter to be quicker)

(我希望后者更快)

And equally, if you are talking about anything otherthan in-memory objects, lambdas are one of your most powerful tools in terms of maintaining type checking (rather than parsing strings all the time).

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

Certainly, there are cases when a simple foreachwith code will be faster than the LINQ version, as there will be fewer invokes to do, and invokes cost a small but measurable time. However, in many cases, the code is simply not the bottleneck, and the simpler code (especially for grouping, etc) is worth a lot more than a few nanoseconds.

当然,在某些情况下,简单foreach的代码会比 LINQ 版本更快,因为要执行的调用更少,并且调用花费的时间很少但可衡量。然而,在很多情况下,代码根本就不是瓶颈,更简单的代码(尤其是分组等)的价值远远超过几纳秒。

Note also that in .NET 4.0 there are additional Expressionnodesfor things like loops, commas, etc. The language doesn't support them, but the runtime does. I mention this only for completeness: I'm certainly not saying you should use manual Expressionconstruction where foreachwould do!

另请注意,在 .NET 4.0 中还有其他Expression节点用于循环、逗号等。语言不支持它们,但运行时支持。我提到这一点只是为了完整性:我当然不是说你应该Expressionforeach什么地方使用手动构建!

回答by Razzie

I'd say that the performance differences are usually so small (and in the case of loops, obviously, if you look at the results of the 2nd article (btw, Jon Skeet has a similar article here)) that you should almost never choose a solution for performance reasons alone, unless you are writing a piece of software where performance is absolutely thenumber one non-functional requirement and you really have to do micro-optimalizations.

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

When to choose what? I guess it depends on the situation but also the person. Just as an example, some people perfer List.Foreach over a normal foreach loop. I personallyprefer the latter, as it is usually more readable, but who am I to argue against this?

什么时候选什么?我想这取决于情况,但也取决于人。举个例子,有些人更喜欢 List.Foreach 而不是普通的 foreach 循环。我个人更喜欢后者,因为它通常更具可读性,但我该反对谁呢?

回答by Dustin Campbell

Rules of thumb:

经验法则:

  1. Write your code to be natural and readable.
  2. Avoid code duplications (lambda expressions might require a little extra diligence).
  3. Optimize only when there's a problem, and only with data to back up what that problem actually is.
  1. 编写自然且可读的代码。
  2. 避免代码重复(lambda 表达式可能需要一些额外的努力)。
  3. 仅在出现问题时进行优化,并且仅使用数据来备份该问题的实际情况。

回答by Daniel Earwicker

If you need recursion, don't use lambdas, or you'll end up getting very distracted!

如果您需要递归,请不要使用 lambda,否则您最终会分心

回答by Rui Craveiro

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.

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

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.

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

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:

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

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

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:

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

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

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.

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

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:

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

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

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

回答by MichaelGG

Any time the lambda simply passes its arguments directly to another function. Don't create a lambda for function application.

任何时候 lambda 只是将其参数直接传递给另一个函数。不要为函数应用程序创建 lambda。

Example:

例子:

var coll = new ObservableCollection<int>();
myInts.ForEach(x => coll.Add(x))

Is nicer as:

更好,因为:

var coll = new ObservableCollection<int>();
myInts.ForEach(coll.Add)

The main exception is where C#'s type inference fails for whatever reason (and there are plenty of times that's true).

主要的例外是 C# 的类型推断因任何原因而失败(而且很多时候都是这样)。

回答by Jerry Nixon

My answer will not be popular.

我的回答不会受欢迎。

I believe Lambda's are 99% always the better choice for three reasons.

我相信 Lambda 始终是 99% 的更好选择,原因有三个。

First, there is ABSOLUTELY nothing wrong with assuming your developers are smart. Other answers have an underlying premise that every developer but you is stupid. Not so.

首先,假设您的开发人员很聪明绝对没有错。其他答案有一个基本前提,即除您之外的每个开发人员都是愚蠢的。不是这样。

Second, Lamdas (et al) are a modern syntax - and tomorrow they will be more commonplace than they already are today. Your project's code should flow from current and emerging conventions.

其次,Lamdas(等人)是一种现代语法——明天它们将比今天更普遍。您的项目代码应该来自当前和新兴的约定。

Third, writing code "the old fashioned way" might seem easier to you, but it's not easier to the compiler. This is important, legacy approaches have little opportunity to be improved as the compiler is rev'ed. Lambdas (et al) which rely on the compiler to expand them can benefit as the compiler deals with them better over time.

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

To sum up:

总结:

  1. Developers can handle it
  2. Everyone is doing it
  3. There's future potential
  1. 开发者可以处理
  2. 每个人都在做
  3. 未来有潜力

Again, I know this will not be a popular answer. And believe me "Simple is Best" is my mantra, too. Maintenance is an important aspect to any source. I get it. But I think we are overshadowing reality with some cliché rules of thumb.

同样,我知道这不会是一个受欢迎的答案。相信我,“简单就是最好的”也是我的口头禅。维护是任何来源的重要方面。我得到它。但我认为我们用一些陈词滥调的经验法则掩盖了现实。

// Jerry

// 杰瑞

回答by nawfal

Lambda expressions are cool. Over older delegatesyntaxthey have a few advantages like, they can be converted to either anonymous function or expression trees, parameter types are inferred from the declaration, they are cleaner and more concise, etc. I see no real value to not use lambda expression when you're in need of an anonymous function. One not so big advantage the earlier style has is that you can omit the parameter declaration totally if they are not used. Like

Lambda 表达式很酷。与旧delegate语法相比,它们有一些优点,例如,它们可以转换为匿名函数或表达式树,从声明中推断出参数类型,它们更清晰、更简洁等。我认为在以下情况下不使用 lambda 表达式没有真正的价值你需要一个匿名函数。早期样式的一个不那么大的优势是,如果不使用它们,您可以完全省略参数声明。喜欢

Action<int> a = delegate { }; //takes one argument, but no argument specified

This is useful when you have to declare an empty delegate that does nothing, but it is not a strongreason enough to not use lambdas.

当你要声明一个空的委托,它什么都不做,这是有用的,但它不是一个强大的足够的理由不使用lambda表达式。

Lambdas let you write quick anonymous methods. Now that makes lambdas meaningless everywhere where anonymous methods go meaningless, ie where named methods make more sense. Over named methods, anonymous methods can be disadvantageous (not a lambda expression per se thing, but since these days lambdas widely represent anonymous methods it is relevant):

Lambda 可让您编写快速的匿名方法。现在这使得 lambda 在匿名方法变得毫无意义的地方变得毫无意义,即命名方法更有意义的地方。在命名方法上,匿名方法可能是不利的(不是 lambda 表达式本身,但由于现在 lambda 广泛代表匿名方法,因此它是相关的):

  1. because it tend to lead to logic duplication (often does, reuse is difficult)

  2. when it is unnecessary to write to one, like:

    //this is unnecessary 
    Func<string, int> f = x => int.Parse(x);
    
    //this is enough
    Func<string, int> f = int.Parse;
    
  3. since writing anonymous iterator block is impossible.

    Func<IEnumerable<int>> f = () => { yield return 0; }; //impossible
    
  4. since recursive lambdas require one more line of quirkiness, like

    Func<int, int> f = null;
    f = x => (x <= 1) ? 1 : x * f(x - 1);
    
  5. well, since reflection is kinda messier, but that is moot isn't it?

  1. 因为它往往会导致逻辑重复(经常会,重用很困难)

  2. 当没有必要写入时,例如:

    //this is unnecessary 
    Func<string, int> f = x => int.Parse(x);
    
    //this is enough
    Func<string, int> f = int.Parse;
    
  3. 因为编写匿名迭代器块是不可能的。

    Func<IEnumerable<int>> f = () => { yield return 0; }; //impossible
    
  4. 因为递归 lambdas 需要更多的怪癖,比如

    Func<int, int> f = null;
    f = x => (x <= 1) ? 1 : x * f(x - 1);
    
  5. 好吧,既然反射有点混乱,但这没有实际意义,不是吗?

Apart from point 3, the rest are not strongreasons not to uselambdas.

除了第3点,其余的都没有很强的理由不使用lambda表达式。

Also see this threadabout what is disadvantageous about Func/Actiondelegates, since often they are used along with lambda expressions.

另请参阅此线程,了解Func/Action委托的缺点,因为它们通常与 lambda 表达式一起使用。