编写一个接受 lambda 表达式的方法
我有一个具有以下签名的方法:
void MyMethod(Delegate d){};
void MyMethod(Expression exp){};
void MyMethod(object obj){};
但是,这无法编译:
MyMethod((int a) => a)
并出现以下错误:
"Cannot convert lambda expression to type 'object' because it is not a delegate type"
为什么这不起作用?
编辑:我知道这有效。我认为在这种情况下,编译器将 lambda 表达式编译为委托门。
void MyMethod(Func<int, int> d){};
亲切的问候,
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.
void MyMethod(Func<int, int> d){};
Kind regards,
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
因为 System.Delegate 类型不是“Delegate”。这只是基类。您必须使用具有正确签名的委托类型。按如下方式定义您的方法:
编辑:
MyMethod(object) 不起作用,因为 lambda 表达式本身没有类型,但该类型是从分配给它的位置的类型推断出来的。所以对象也不起作用。您必须使用具有正确签名的委托类型。
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:
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.
使用情况:
C# 是一种静态类型语言。编译器需要知道它处理的所有内容的类型。 Lambda 有点难以确定,有时编译器无法弄清楚。在上面的示例中,如果 MyMethod 接受一个对象,编译器无法确定
x
是一个int
(我的示例很简单,但没有任何内容表明它可以不会更复杂且更难确定)。因此,我必须更加明确地定义采用 lambda 的方法。in use:
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 anint
(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.类似于
(int a) => 的 lambda a
将适合任何接受int
并返回int
的委托。Func
只是一个示例,您可以使用delegate int Foo(int x);
轻松地自行声明一个示例。事实上,这个 lambda 表达式甚至适合接受int
并返回double
的委托,因为 lambda (a
) 的结果是隐式转换为double
。为了使 lambda 能够分配给它适合的所有委托类型,lambda 本身并不具有固有的类型。相反,只要可能,它就会采用您正在使用的委托的类型。 (
(int a) => a
当然不能分配给Func
。) 和我定义的
Foo
delegate 当然可以转换为Delegate
,lambda 不能直接转换为Delegate
因为它目前尚不清楚其实际签名是什么。委托 d = (int a) => 之后a,d
会是Foo
,或Func
,甚至是Func;?所有这些都是有效的可能性,并且编译器不知道您的意图。它可以做出最好的猜测,但 C# 不是那种进行这种猜测的语言。这也是为什么你不能做类似
var = (int a) =>; 的事情。一个。
我确实认为编译器为
Delegate d = (int a) => 给出的错误消息是: a;
非常不清楚:直观上您会认为
Delegate
是委托类型,但事实并非如此。 :)A lambda like
(int a) => a
will fit any delegate that takes anint
and returns anint
.Func<int,int>
is just a single example, and you could easily declare one yourself withdelegate int Foo(int x);
. In fact this lambda expression will even fit a delegate that takes anint
and returns adouble
, because the result of the lambda (a
) is implicitly convertible todouble
.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 toFunc<byte, byte>
of course.)While both
Func<int, int>
and theFoo
delegate I defined can of course be converted toDelegate
, a lambda can not be directly converted toDelegate
because it is unclear what its actual signature would then be. AfterDelegate d = (int a) => a
, wouldd
beFoo
, orFunc<int, int>
, or evenFunc<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 likevar = (int a) => a
.I do think the error message that the compiler gives for
Delegate d = (int a) => a;
is very unclear:Intuitively you would think
Delegate
is a delegate type, but that's not how things work. :)试试这个:
您需要一个强类型委托作为该方法的参数。其他调用失败的原因是 C# 编译器不允许您将 lambda 表达式传递给需要
Object
的方法,因为 lambda 表达式不一定在所有情况下都是委托。同样的规则也适用于将 lambda 表达式作为Delegate
传递。当您将 lambda 传递给函数(如我上面所示)时,编译可以安全地假设您希望将 lambda 表达式转换为特定的委托类型并执行此操作。
Try this:
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 aDelegate
.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.
这只是编译器的本质,当您将委托对象作为
Delegate
类型的参数传递时,您需要将其显式转换为Delegate
。事实上,lambda 表达式使事情变得更加复杂,因为在这种情况下它们不能隐式转换为委托。您需要的是双重强制转换,如下所示:
这当然对应于方法签名:
根据您的情况,您可能需要定义
Func
类型的参数,而不是委托(尽管我会犹豫是否要添加重载,因为老实说它会增加不必要的复杂性)。
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 typeDelegate
. In fact, lambda expressions complicate things even further in that they are not implicitly convertable to delegates in this case.What you require is a double cast, as such:
which of course corresponds to the method signature:
Depending on your situation, you may want to define a parameter of type
Func<int>
rather thanDelegate
(though I would hesitate adding an overload, just because it adds unnecessary complexity in honesty).失败的原因与“object del = (int a) => a”甚至“var del = (int a) => a”这样的表达式失败的原因相同。您可能认为编译器可以计算出 lambda 表达式的类型,因为您显式给出了参数的类型,但即使知道该表达式采用 int 并返回 int,也可以转换许多委托类型到。 Func 委托类型是最常用于此类泛型函数的类型,但这只是一种约定,编译器不知道任何内容。
您需要做的是将 lambda 表达式转换为具体的委托类型,以便让编译器选择委托重载,可以使用普通的转换语法 (Func)((int a) => a),也可以使用委托构造函数语法 new Func((int a) => a).
另外,您通常不想使用非类型化的 Delegate 类,除非您需要根据它接受的参数数量来不同地调用某些东西。对于回调之类的事情,接受 Func 或 Action 几乎总是更好。
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.
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).
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.