我有一个带有以下签名的方法:
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表达式编译为delgate。
void MyMethod(Func<int, int> d){};
亲切的问候,
答案 0 :(得分:20)
因为System.Delegate类型不是“委托”。它只是基类。您必须使用具有正确签名的委托类型。按如下方式定义您的方法:
void MyMethod(Func<int, int> objFunc)
编辑:
MyMethod(object)不起作用,因为lambda表达式没有自己的类型,但是从它所分配的位置类型推断出类型。所以对象也不起作用。您必须使用具有正确签名的委托类型。
答案 1 :(得分:13)
void MyMethod(Action<int> lambdaHereLol)
{
lambdaHereLol(2);
}
正在使用中:
var hurrDurr = 5;
MyMethod(x => Console.Write(x * hurrDurr));
C#是一种静态类型语言。编译器需要知道它处理的所有内容的类型。 Lambdas有点难以确定,有时编译器无法弄明白。在上面的例子中,如果MyMethod接受了一个对象,编译器就无法确定x
是int
(我的例子很简单,但是没有什么可以说它不会复杂得多并且更难确定)。所以我必须更明确地定义采用我的lambda的方法。
答案 2 :(得分:3)
像(int a) => a
这样的lambda将适合任何需要int
并返回int
的委托。 Func<int,int>
只是一个示例,您可以轻松地使用delegate int Foo(int x);
声明一个。事实上,这个lambda表达式甚至适合采用int
并返回double
的委托,因为lambda(a
)的结果可以隐式转换为double
。
为了将lambda分配给它适合的所有委托类型,lambda本身并不具有类型。相反,它只需要你使用它的代表类型,只要这是可能的。 ((int a) => a
当然不能分配到Func<byte, byte>
。)
虽然我定义的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
。
我认为编译器为Delegate d = (int a) => a;
提供的错误消息非常不清楚:
无法将lambda表达式转换为'System.Delegate'类型,因为它不是委托类型
直觉上你会认为Delegate
是委托类型,但事情并非如此。 :)
答案 3 :(得分:2)
试试这个:
void MyMethod(Action<int> func) { }
您需要强类型委托作为方法的参数。其他调用失败的原因是因为C#编译器不允许您将lambda表达式传递给期望Object
的方法,因为lambda表达式在所有情况下都不一定总是委托。同样的规则适用于将lambda表达式作为Delegate
传递。
当您将lambda传递给我上面显示的函数时,编译可以安全地假设您希望将lambda表达式转换为特定的委托类型并执行此操作。
答案 4 :(得分:0)
当将委托对象作为Delegate
类型的参数传递时,您需要将委托对象显式地转换为Delegate
,这就是编译器的本质。事实上,lambda表达式使事情进一步复杂化,因为在这种情况下它们不能隐式转换为委托。
你需要的是双重演员,如下:
MyMethod((Delegate)(Func<int, int>)((int a) => a));
当然对应于方法签名:
void MyMethod(Delegate d);
根据您的具体情况,您可能需要定义Func<int>
类型的参数而不是Delegate
(尽管我会犹豫是否会添加过载,因为它会增加不必要的诚实复杂性。)
答案 5 :(得分:0)
失败的原因与“object del =(int a)=&gt; a”或甚至“var del =(int a)=&gt; a”这样的表达式失败的原因相同。您可能认为编译器可以找出lambda表达式的类型,因为您明确地给出了参数的类型,但即使知道表达式采用int并返回int,也可以转换许多委托类型至。 Func委托类型是最常用于泛型函数的类型,但这只是一个约定,而编译器并不知道。
您需要做的是将lambda表达式强制转换为具体的委托类型,以便让编译器选择Delegate重载,使用普通的强制转换语法(Func)((int a)=&gt; a),或者使用委托构造函数语法new Func((int a)=&gt; a)。
此外,您通常不希望使用无类型的Delegate类,除非您需要根据它接受的参数数量调用不同的内容。接受回调等事情的Func或Action几乎总是更好。