C# new Action() 和 lambda 有什么区别?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/765966/
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-05 00:17:44  来源:igfitidea点击:

What is the difference between new Action() and a lambda?

c#.net-3.5delegateslambda

提问by George Mauer

So when I write something like this

所以当我写这样的东西时

Action action = new Action(()=>_myMessage = "hello");

Refactor Pro! Highlights this as a redundant delegate creation and allows me to to shorten it to

重构专业版!将此突出显示为冗余委托创建,并允许我将其缩短为

Action action = () => _myMessage="hello";

And this usually works great. Usually, but not always. For example, Rhino Mocks has an extension method named Do:

这通常效果很好。 通常,但并非总是如此。例如,Rhino Mocks 有一个名为 Do 的扩展方法:

IMethodOptions<T> Do(Delegate action);

Here, passing in the first version works, but the second doesn't. What exactly is going on under the covers here?

在这里,传入第一个版本有效,但第二个版本无效。这里到底发生了什么?

采纳答案by Jon Skeet

The first version is effectively doing:

第一个版本有效地执行:

Action tmp = () => _myMessage = "hello";
var action = new Action(tmp);

The problem you're running into is that the compiler has to know what kind of delegate (or expression tree) the lambda expression should be converted into. That's why this:

您遇到的问题是编译器必须知道 lambda 表达式应该转换成什么样的委托(或表达式树)。这就是为什么:

var action = () => _myMessage="hello";

actually doesn't compile - it could be anydelegate type with no parameters and either no return value or the same return type as _myMessage(which is presumably string). For instance, all of these are valid:

实际上不会编译 - 它可以是任何没有参数的委托类型,也可以是没有返回值或与_myMessage(大概是string)相同的返回类型。例如,所有这些都是有效的:

Action action = () => _myMessage="hello";
Func<string> action = () => _myMessage="hello";
MethodInvoker action = () => _myMessage="hello";
Expression<Action> = () => _myMessage="hello";
// etc

How could the C# compiler work out what type actionwas meant to be, if it were declared with var?

如果 C# 编译器action是用var.

The simplest way to get round this when calling a method (for your Rhino Mocks example) is to cast:

在调用方法时(对于您的 Rhino Mocks 示例),解决此问题的最简单方法是强制转换:

methodOptions.Do((Action) (() => _myMessage = "hello"));

回答by JaredPar

Have you verified the second line actually compiles? It should not compile because C# does not support assigning a lambda expression to an implicitly typed variable (CS0815). This line will work in VB.Net though because it supports anonymous delegate creation (starting in VB 9.0).

你有没有验证第二行实际编译?它不应编译,因为 C# 不支持将 lambda 表达式分配给隐式类型变量 (CS0815)。这行代码将在 VB.Net 中工作,因为它支持匿名委托创建(从 VB 9.0 开始)。

The Rhino Mocks version does not compile for the same reason the second line should not compile. C# will not automatically infer a type for a lambda expression. Lambda expressions must be used in a context where it is possible to determine the delegate type they are intended to fulfill. The first line works great because the intended type is clear: Action. The Rhino Mocks version does not work because Delegate is more akin to an abstract delegate type. It must be a concrete delegate type such as Action or Func.

Rhino Mocks 版本不能编译的原因与第二行不能编译的原因相同。C# 不会自动推断 lambda 表达式的类型。Lambda 表达式必须在可以确定它们要实现的委托类型的上下文中使用。第一行很有效,因为预期的类型很明确:Action。Rhino Mocks 版本不起作用,因为 Delegate 更类似于抽象委托类型。它必须是具体的委托类型,例如 Action 或 Func。

For a detailed discussion on this topic, you should read Eric Lippert's blog entries on the subject: http://blogs.msdn.com/ericlippert/archive/2007/01/11/lambda-expressions-vs-anonymous-methods-part-two.aspx

有关此主题的详细讨论,您应该阅读 Eric Lippert 关于该主题的博客条目:http: //blogs.msdn.com/ericlippert/archive/2007/01/11/lambda-expressions-vs-anonymous-methods-part -two.aspx

回答by Avjol Sakaj

Action is a special type of delegate. So, if you use lambda will not understand which type you want to use since there are many (Action, Func,...).

动作是一种特殊类型的委托。因此,如果您使用 lambda 将无法理解您要使用哪种类型,因为有很多(Action, Func,...)

To overcome this need for cast (which is slow in most of the cases)you can change the parameter of the base function from Delegate to Action:

为了克服这种强制转换的需要(在大多数情况下这很慢),您可以将基本函数的参数从 Delegate 更改为 Action:

IMethodOptions<T> Do(Action action);

This way you can use both statements and will not have any different:

这样你就可以使用这两个语句并且不会有任何不同:

Action action = new Action(()=>_myMessage = "hello"); 
Action action = () => _myMessage="hello";

If this is not possible then i suggest to use new Action(() => {})instead of casting, it would be faster.

如果这是不可能的,那么我建议使用new Action(() => {})而不是强制转换,这样会更快。

Please read the following link for more information on Action and Delegate: https://docs.microsoft.com/en-gb/dotnet/api/system.action?view=netframework-4.7.1#definition

请阅读以下链接以获取有关 Action 和 Delegate 的更多信息:https: //docs.microsoft.com/en-gb/dotnet/api/system.action?view =netframework-4.7.1# definition