使用 C# 方法组(如果可用)有什么好处吗?
在处理诸如 List
之类的内容时,您可以编写以下内容:
list.ForEach(x => Console.WriteLine(x));
或者您可以使用方法组来执行相同的操作:
list.ForEach(Console.WriteLine);
我更喜欢第二行代码,因为它对我来说看起来更干净,但这有什么好处吗?
When dealing with something like a List<string>
you can write the following:
list.ForEach(x => Console.WriteLine(x));
or you can use a method group to do the same operation:
list.ForEach(Console.WriteLine);
I prefer the second line of code because it looks cleaner to me, but are there any benefits to this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
就我个人而言,我也更喜欢第二种,因为调试起来不那么混乱,但在这种情况下,我认为这只是风格问题,因为它们最终都完成了相同的事情。
Personally I also prefer the second because it's less confusing to debug, but in this case I think it's just a matter of style since they both end up getting the same thing done.
除了让喜欢方法组的人更愉快、让不喜欢方法组的人烦恼之外,没有任何实际好处。此外,它还会使您的代码与早期编译器不兼容。
-奥辛
No tangible benefits other than making it more pleasant to people who like method groups, and annoy people who dislike them [should that please you.] Also, it makes your code incompatible with earlier compilers.
-Oisin
正如其他人所指出的,存在由 lambda 引起的额外不必要的间接层。然而,也存在细微的语言差异。例如,在 C# 3 中,尝试执行返回类型推断时,泛型类型推断在
M(F)
上的工作方式与在M(x=>F(x))
上的工作方式不同。有关详细信息,请参阅:
https://learn.microsoft.com/en-us/archive/blogs/ericlippert/c-3-0-return-type-inference-does-not-work-on-方法组
和后续:
https://learn.microsoft.com/en-us/archive/blogs/ericlippert/method-type-inference-changes-part-zero
As others have noted, there is an extra unnecessary layer of indirection induced by the lambda. However, there are subtle language differences as well. For example, in C# 3 generic type inference works differently on
M(F)
than onM(x=>F(x))
when attempting to perform return type inference.For details see:
https://learn.microsoft.com/en-us/archive/blogs/ericlippert/c-3-0-return-type-inference-does-not-work-on-method-groups
and the follow-up:
https://learn.microsoft.com/en-us/archive/blogs/ericlippert/method-type-inference-changes-part-zero
我相信这是有好处的。在第一种情况下,您正在创建调用
Console.Writeline(string)
函数的匿名方法,而在另一种情况下,您只是将引用传递给现有函数。I believe that there is a benefit. In first case you are creating anonymous method which calls
Console.Writeline(string)
function while in the other case you are just passing the reference to existing function.是的;第一个实际上可能会导致不必要的额外临时调用发生;将
x
传递给一个简单调用Console.WriteLine(x);
的方法您不需要执行第一个操作,因为 Console.WriteLine 已经是一个匹配的方法ForEach 正在寻找的签名。Yes; the first actually can cause an unnecessary extra, interim call to happen; passing
x
in to a method that simply callsConsole.WriteLine(x);
You don't need to do the first one because Console.WriteLine already is a method which matches the signature that ForEach is looking for.好吧,让我们看看会发生什么。
这将被编译成以下 IL。
请注意方法组方法如何创建一次性使用的
Action
委托,而 lambda 表达式方法如何创建隐藏的匿名委托字段并在必要时对其进行内联初始化。请注意IL_000a
处的brtrue
指令。Well, let's take a look and see what happens.
This gets compiled into the following IL.
Notice how the method group approach creates an
Action<T>
delegate for one time use and the lambda expression approach creates a hidden anonymous delegate field and does an inline initialization of it if necessary. Noticebrtrue
instruction atIL_000a
.使用 lambda 表达式时存在额外的间接级别。对于这样的非闭包表达式,您只需在中间进行一个额外的方法调用,正如其他人提到的那样。
但还是有一些有趣的差异。在第二种情况下,每次调用时都会创建一个新的委托实例。对于前者,委托创建一次并缓存为隐藏字段,因此如果您调用很多,您将节省分配。
此外,如果您将局部变量引入 lambda 表达式,它就会变成一个闭包,并且将创建一个新类来保存此信息,而不仅仅是生成一个局部方法,这意味着在那里进行了额外的分配。
There is an extra level of indirection when using the lambda expression. With a non-closure expression like that, you'll simply have an extra method call in-between, as mentioned by others.
There are a few interesting differences though. In the second case, a new delegate instance is being created on each call. For the former, the delegate is created once and cached as a hidden field, so if you're calling a lot you'll save on allocations.
Additionally, if you introduce a local variable into the lambda expression, it becomes a closure and instead of just a local method being generated, a new class will be created to hold this information, meaning an extra allocation there.