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);
}
}
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());
}
}
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.
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.
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);
}
}
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:
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.
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");
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.
I believe Lambda's are 99% always the better choice for three reasons.
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.
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.
To sum up:
Developers can handle it
Everyone is doing it
There's future potential
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.
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.
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 other than in-memory objects, lambdas are one of your most powerful tools in terms of maintaining type checking (rather than parsing strings all the time).
Certainly, there are cases when a simple foreach with 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.
Note also that in .NET 4.0 there are additional Expression nodes for 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 Expression construction where foreach would do!
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 the number one non-functional requirement and you really have to do micro-optimalizations.
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 personally prefer the latter, as it is usually more readable, but who am I to argue against this?
Lambda expressions are cool. Over older delegate syntax they 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
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 strong reason enough to not use lambdas.
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):
because it tend to lead to logic duplication (often does, reuse is difficult)
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;
since writing anonymous iterator block is impossible.
发布评论
评论(9)
尽管我将重点关注第一点,但我首先对整个性能问题提出我的 2 美分。 除非差异很大或使用量很大,否则通常我不会担心微秒,因为添加微秒后不会对用户造成任何明显的差异。 我强调,只有在考虑非密集调用方法时我才不在乎。 我确实有特殊性能考虑的地方是我设计应用程序本身的方式。 我关心缓存、线程的使用、调用方法的巧妙方法(是进行多次调用还是尝试只进行一次调用)、是否池化连接等等。事实上我通常不关心不关注原始性能,而是关注可扩展性。 我并不关心它对于单个用户来说是否运行得好一点纳秒,但我非常关心是否能够在没有注意到影响的情况下为系统加载大量并发用户。
话虽如此,这是我对第一点的看法。我喜欢匿名方法。 它们给了我很大的灵活性和代码的优雅。 匿名方法的另一个重要功能是它们允许我直接使用容器方法中的局部变量(当然,从 C# 角度来看,而不是从 IL 角度来看)。 他们经常为我节省大量代码。 什么时候使用匿名方法? 每次我需要的代码片段在其他地方都不需要。 如果它在两个不同的地方使用,我不喜欢复制粘贴作为重用技术,所以我将使用普通的委托。 所以,就像 shoosh 回答的那样,代码重复是不好的。 理论上,不存在性能差异,因为匿名是 C# 技巧,而不是 IL 东西。
我对匿名方法的大部分看法都适用于 lambda 表达式,因为后者可以用作表示匿名方法的紧凑语法。 让我们假设以下方法:
它接收一个字符串数组,并且对于每个字符串,它将调用传递给它的方法。 如果该方法返回 true,则会显示“Found...”。 您可以通过以下方式调用此方法:
但是,您也可以通过以下方式调用它:
两者之间的 IL 没有区别,只是使用 Lambda 表达式的方法更具可读性。 再次强调,不会对性能产生影响,因为这些都是 C# 编译器技巧(而不是 JIT 编译器技巧)。 正如我不认为我们过度使用匿名方法一样,我也不认为我们过度使用 Lambda 表达式来表示匿名方法。 当然,相同的逻辑适用于重复的代码:不要使用 lambda,使用常规委托。 还有其他限制导致您返回匿名方法或普通委托,例如 out 或 ref 参数传递。
Lambda 表达式的另一个优点是不需要使用完全相同的语法来表示匿名方法。 Lambda 表达式还可以表示……你猜对了,表达式。 举个例子:
注意略有不同的签名。 第二个参数接收表达式而不是委托。 调用此方法的方法是:
这与我们在使用 lambda 创建匿名方法时进行的调用完全相同。 这里的区别在于,我们不是创建匿名方法,而是创建表达式树。 正是由于这些表达式树,我们可以将 lambda 表达式转换为 SQL,这就是 Linq 2 SQL 所做的,例如,而不是在引擎中为每个子句执行内容,如Where、Select 等。无论您是创建匿名方法还是发送表达式,调用语法都是相同的。
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.
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.
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:
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:
But, you can also call it the following way:
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.
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:
Notice the slightly different signature. The second parameter receives an expression and not a delegate. The way to call this method would be:
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.
我的回答不会受欢迎。
我相信 99% 的 Lambda 总是更好的选择,原因有以下三个。
首先,假设你的开发人员很聪明,这绝对没有错。 其他答案有一个基本前提:除了你之外的每个开发人员都是愚蠢的。 并非如此。
其次,Lamda(等)是一种现代语法 - 明天它们将比今天更加普遍。 您的项目代码应该遵循当前和新兴的约定。
第三,“老式方式”编写代码对您来说可能看起来更容易,但对编译器来说却并不容易。 这很重要,随着编译器的更新,遗留方法几乎没有机会得到改进。 依赖编译器扩展它们的 Lambda(等)可以受益,因为随着时间的推移,编译器可以更好地处理它们。
总结一下:
同样,我知道这不会是一个受欢迎的答案。 相信我,“简单就是最好”也是我的座右铭。 维护对于任何来源来说都是一个重要方面。 我得到它。 但我认为我们用一些陈词滥调的经验法则掩盖了现实。
// 杰瑞
My answer will not be popular.
I believe Lambda's are 99% always the better choice for three reasons.
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.
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.
To sum up:
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
代码重复。
如果您发现自己多次编写同一个匿名函数,那么它不应该是一个。
Code duplication.
If you find yourself writing the same anonymous function more than once, it shouldn't be one.
好吧,当我们讨论委托的使用时,lambda 和匿名方法之间不应该有任何区别——它们是相同的,只是语法不同。 从运行时的角度来看,命名方法(用作委托)也是相同的。 那么,区别在于使用委托与内联代码之间 - 即
(我希望后者更快)
同样,如果您谈论的是内存中对象之外的任何东西,就维护类型检查(而不是一直解析字符串)而言,lambda 是最强大的工具之一。
当然,在某些情况下,带有代码的简单
foreach
会比 LINQ 版本更快,因为需要执行的调用更少,并且调用花费的时间虽小但可衡量。 然而,在许多情况下,代码根本不是瓶颈,而且更简单的代码(尤其是分组等)的价值远远超过几纳秒。另请注意,在 .NET 4.0 中还有 其他
Expression
节点 用于循环、逗号等。语言不支持它们,但运行时支持。 我提到这一点只是为了完整性:我当然不是说您应该使用手动Expression
构造,而foreach
会这样做!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.
(where I would expect the latter to be quicker)
And equally, if you are talking about anything other than in-memory objects, lambdas are one of your most powerful tools in terms of maintaining type checking (rather than parsing strings all the time).
Certainly, there are cases when a simple
foreach
with 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.Note also that in .NET 4.0 there are additional
Expression
nodes for 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 manualExpression
construction whereforeach
would do!我想说,性能差异通常很小(在循环的情况下,显然,如果您查看第二篇文章的结果(顺便说一句,Jon Skeet 有一篇类似的文章 这里)) 你几乎永远不应该仅仅出于性能原因选择解决方案,除非你正在编写一个软件其中性能绝对是第一位的非功能性需求,您确实必须进行微优化。
什么时候选择什么? 我想这取决于情况,也取决于人。 举个例子,有些人更喜欢 List.Foreach 而不是普通的 foreach 循环。 我个人更喜欢后者,因为它通常更具可读性,但我有什么资格反对这一点呢?
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 the number one non-functional requirement and you really have to do micro-optimalizations.
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 personally prefer the latter, as it is usually more readable, but who am I to argue against this?
经验法则:
Rules of thumb:
任何时候 lambda 都会将其参数直接传递给另一个函数。 不要为函数应用程序创建 lambda。
示例:
更好的是:
主要的例外是 C# 的类型推断由于某种原因而失败(很多时候确实如此)。
Any time the lambda simply passes its arguments directly to another function. Don't create a lambda for function application.
Example:
Is nicer as:
The main exception is where C#'s type inference fails for whatever reason (and there are plenty of times that's true).
如果需要递归,请不要使用 lambda,否则你最终会变得非常分心!
If you need recursion, don't use lambdas, or you'll end up getting very distracted!
Lambda 表达式很酷。 相对于旧的
委托
语法,它们有一些优点,例如,它们可以转换为匿名函数或表达式树,参数类型从声明中推断出来,它们更干净,更多当您需要匿名函数时,我认为不使用 lambda 表达式没有任何实际价值。 早期风格的一个不太大的优点是,如果不使用参数声明,您可以完全省略它们。 当您必须声明一个不执行任何操作的空委托时,这很有用,但这并不是不使用 lambda 的强有力理由。
Lambda 允许您编写快速的匿名方法。 现在,在匿名方法变得毫无意义的地方,即命名方法更有意义的地方,lambda 就变得毫无意义。 在命名方法上,匿名方法可能是不利的(本身不是 lambda 表达式,但由于如今 lambda 广泛代表匿名方法,因此它是相关的):
因为它往往会导致逻辑重复(经常这样做,重用很困难)
当不需要写入时,例如:
因为不可能写入匿名迭代器块。
因为递归 lambda 需要多一行奇怪的内容,例如
好吧,因为反射有点混乱,但这没有实际意义,不是吗?
除了第 3 点之外,其余的都不是不使用 lambda 的强有力理由。
另请参阅此 线程 了解
的缺点Func/Action
委托,因为它们经常与 lambda 表达式一起使用。Lambda expressions are cool. Over older
delegate
syntax they 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. LikeThis is useful when you have to declare an empty delegate that does nothing, but it is not a strong reason enough to not use lambdas.
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):
because it tend to lead to logic duplication (often does, reuse is difficult)
when it is unnecessary to write to one, like:
since writing anonymous iterator block is impossible.
since recursive lambdas require one more line of quirkiness, like
well, since reflection is kinda messier, but that is moot isn't it?
Apart from point 3, the rest are not strong reasons not to use lambdas.
Also see this thread about what is disadvantageous about
Func/Action
delegates, since often they are used along with lambda expressions.