C# 编写一个接受 lambda 表达式的方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1594171/
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
Write a method which accepts a lambda expression
提问by SharePoint Newbie
I have a method with the following signature:
我有一个具有以下签名的方法:
void MyMethod(Delegate d){};
void MyMethod(Expression exp){};
void MyMethod(object obj){};
However, this fails to compile:
但是,这无法编译:
MyMethod((int a) => a)
with the following error:
出现以下错误:
"Cannot convert lambda expression to type 'object' because it is not a delegate type"
Why doesn't this work?
为什么这不起作用?
Edit: I know that this works. The compiler compiles the lambda expression to a delgate in this case I think.
编辑:我知道这有效。我认为在这种情况下,编译器将 lambda 表达式编译为 delgate。
void MyMethod(Func<int, int> d){};
Kind regards,
亲切的问候,
采纳答案by Maximilian Mayerl
Because the type System.Delegate isn't a "Delegate". It's just the base class. You have to use a delegate type with the correct signature. Define your Method as follows:
因为 System.Delegate 类型不是“委托”。这只是基类。您必须使用具有正确签名的委托类型。定义你的方法如下:
void MyMethod(Func<int, int> objFunc)
EDIT:
编辑:
MyMethod(object) doesn't work because a lambda expression has no type at it's own, but the type is inferred from the type of the location it is assigned to. So object doesn't work either. You HAVE to use a delegate type with the correct signature.
MyMethod(object) 不起作用,因为 lambda 表达式本身没有类型,但该类型是从分配给它的位置的类型推断出来的。所以对象也不起作用。您必须使用具有正确签名的委托类型。
回答by SharePoint Newbie
void MyMethod(Action<int> lambdaHereLol)
{
lambdaHereLol(2);
}
in use:
正在使用:
var hurrDurr = 5;
MyMethod(x => Console.Write(x * hurrDurr));
C# is a statically typed language. The compiler needs to know the Type of everything it deals with. Lambdas are a bit hard to nail down, and sometimes the compiler can't figure it out. In my example above, if MyMethod took an object, the compiler couldn't figure out that x
is an int
(my example is simple, but there's nothing that says it can't be much more complex and harder to determine). So I have to be more explicit in defining the method that takes my lambda.
C# 是一种静态类型语言。编译器需要知道它处理的所有内容的类型。Lambda 有点难以确定,有时编译器无法弄清楚。在我上面的示例中,如果 MyMethod 接受一个对象,编译器无法确定它x
是一个int
(我的示例很简单,但没有任何内容表明它不能更复杂和更难确定)。所以我必须更明确地定义采用我的 lambda 的方法。
回答by Andrew Hare
Try this:
尝试这个:
void MyMethod(Action<int> func) { }
You need to a strongly-typed delegate as a parameter to the method. The reason the other calls fail is because the C# compiler will not allow you to pass a lambda expression to a method expecting an Object
because a lambda expression isn't necessarily always a delegate in all cases. This same rule applies for passing the lambda expression as a Delegate
.
您需要一个强类型委托作为该方法的参数。其他调用失败的原因是 C# 编译器不允许您将 lambda 表达式传递给需要 的方法,Object
因为 lambda 表达式不一定在所有情况下都是委托。同样的规则适用于将 lambda 表达式作为 a 传递Delegate
。
When you pass the lambda to a function like I have showed above, the compile can safely assume that you want the lambda expression to be converted to a specific delegate type and does so.
当您将 lambda 传递给我上面展示的函数时,编译器可以安全地假设您希望将 lambda 表达式转换为特定的委托类型并这样做。
回答by Noldorin
It's simply the nature of the compiler that you need to explicitly cast a delegate object to Delegate
when passing it as a parameter of type Delegate
. In fact, lambda expressions complicate things even further in that they are not implicitly convertable to delegates in this case.
这只是编译器的性质,在将委托对象Delegate
作为 type 的参数传递时,您需要将其显式转换为Delegate
。事实上,lambda 表达式使事情更加复杂,因为在这种情况下它们不能隐式转换为委托。
What you require is a double cast, as such:
您需要的是双重演员,例如:
MyMethod((Delegate)(Func<int, int>)((int a) => a));
which of course corresponds to the method signature:
这当然对应于方法签名:
void MyMethod(Delegate d);
Depending on your situation, you may want to define a parameter of type Func<int>
rather than Delegate
(though I would hesitate adding an overload, just because it adds unnecessary complexity in honesty).
根据您的情况,您可能想要定义一个 type 参数Func<int>
而不是Delegate
(尽管我会犹豫添加重载,只是因为它会增加不必要的复杂性)。
回答by Joren
A lambda like (int a) => a
will fit any delegate that takes an int
and returns an int
. Func<int,int>
is just a single example, and you could easily declare one yourself with delegate int Foo(int x);
. In fact this lambda expression will even fit a delegate that takes an int
and returns a double
, because the result of the lambda (a
) is implicitly convertible to double
.
一个 lambda like(int a) => a
将适合任何接受int
并返回一个的委托int
。Func<int,int>
只是一个例子,你可以很容易地用delegate int Foo(int x);
. 事实上,这个 lambda 表达式甚至适合接受 anint
并返回 a的委托double
,因为 lambda( a
)的结果可以隐式转换为double
.
In order for a lambda to be assignable to all the delegate types that it would fit, the lambda itself doesn't inherently have a type. Instead it takes on the type of the delegate you're using it as, as long as that's possible. ((int a) => a
can't be assigned to Func<byte, byte>
of course.)
为了让 lambda 可以分配给它适合的所有委托类型,lambda 本身并没有固有的类型。相反,只要可能,它就会采用您使用它的委托类型。(当然(int a) => a
不能分配给Func<byte, byte>
。)
While both Func<int, int>
and the Foo
delegate I defined can of course be converted to Delegate
, a lambda can not be directly converted to Delegate
because it is unclear what its actual signature would then be. After Delegate d = (int a) => a
, would d
be Foo
, or Func<int, int>
, or even Func<int, double>
? All are valid possibilities, and the compiler has no idea what you intended. It could make a best guess, but C# is not the kind of language that does that kind of guesswork. This is also why you can't do something like var = (int a) => a
.
虽然我定义Func<int, int>
的Foo
委托和委托当然都可以转换为Delegate
,但 lambda 不能直接转换为,Delegate
因为不清楚它的实际签名是什么。之后Delegate d = (int a) => a
,就d
可以Foo
,或者Func<int, int>
,甚至Func<int, double>
?所有都是有效的可能性,编译器不知道你的意图。它可以做出最好的猜测,但 C# 不是那种进行这种猜测的语言。这也是为什么你不能做类似的事情var = (int a) => a
。
I do think the error message that the compiler gives for Delegate d = (int a) => a;
is very unclear:
我确实认为编译器给出的错误消息Delegate d = (int a) => a;
非常不清楚:
Cannot convert lambda expression to type 'System.Delegate' because it is not a delegate type
无法将 lambda 表达式转换为类型“System.Delegate”,因为它不是委托类型
Intuitively you would think Delegate
is a delegate type, but that's not how things work. :)
直觉上你会认为Delegate
是委托类型,但这不是事情的工作方式。:)
回答by SoftMemes
The reason this fails is the same reason an expression like "object del = (int a) => a" or even "var del = (int a) => a" fails. You might think that the compiler could figure out the type of your lambda expression since you explicitly give the type of the argument, but even knowing that the expression takes an int and returns an int, there are a number of delegate types it could be converted to. The Func delegate type is the one most used for generic functions such as this, but that is just a convention and nothing the compiler is aware of.
失败的原因与“object del = (int a) => a”甚至“var del = (int a) => a”之类的表达式失败的原因相同。您可能认为编译器可以确定 lambda 表达式的类型,因为您明确给出了参数的类型,但即使知道该表达式接受一个 int 并返回一个 int,也有许多委托类型可以转换到。Func 委托类型是最常用于诸如此类的泛型函数的类型,但这只是一种约定,编译器对此一无所知。
What you need to do is to cast the lambda expression to a concrete delegate type in order to have the compiler select the Delegate overload, either using the normal cast syntax (Func)((int a) => a), or using the delegate constructor syntax new Func((int a) => a).
您需要做的是将 lambda 表达式转换为具体的委托类型,以便编译器选择委托重载,或者使用正常的转换语法 (Func)((int a) => a),或者使用委托构造函数语法 new Func((int a) => a)。
Also, you normally do not want to use the untyped Delegate class unless you need to invoke something differently depending on the number of argument it accepts. It's almost always better to accept a Func or Action for things like callbacks.
此外,您通常不想使用无类型的 Delegate 类,除非您需要根据它接受的参数数量调用不同的东西。对于回调之类的事情,接受 Func 或 Action 几乎总是更好。