编写一个接受lambda表达式的方法

时间:2009-10-20 12:13:22

标签: c# 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表达式编译为delgate。

void MyMethod(Func<int, int> d){};

亲切的问候,

6 个答案:

答案 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接受了一个对象,编译器就无法确定xint(我的例子很简单,但是没有什么可以说它不会复杂得多并且更难确定)。所以我必须更明确地定义采用我的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之后,dFooFunc<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几乎总是更好。