繁体   English   中英

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

[英]Write a method which accepts a lambda expression

我有一个带有以下签名的方法:

 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){};

亲切的问候,

因为System.Delegate类型不是“委托”。 它只是基类。 您必须使用具有正确签名的委托类型。 定义您的方法如下:

void MyMethod(Func<int, int> objFunc)

编辑:

MyMethod(对象)不起作用,因为lambda表达式没有自己的类型,但是类型是从它所分配的位置类型推断出来的。 所以对象也不起作用。 您必须使用具有正确签名的委托类型。

void MyMethod(Action<int> lambdaHereLol)
{
    lambdaHereLol(2);
}

正在使用:

var hurrDurr = 5;
MyMethod(x => Console.Write(x * hurrDurr));

C#是一种静态类型语言。 编译器需要知道它处理的所有内容的类型。 Lambdas有点难以确定,有时编译器无法弄明白。 在我上面的例子中,如果MyMethod接受了一个对象,编译器就无法弄清楚x是一个int (我的例子很简单,但没有任何东西说它不会复杂得多,也很难确定)。 所以我必须更明确地定义采用我的lambda的方法。

lambda like (int a) => a将适合任何接受int并返回int委托。 Func<int,int>只是一个例子,您可以使用delegate int Foo(int x);轻松地声明一个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 ,将dFoo ,或Func<int, int>或甚至Func<int, double> 所有都是有效的可能性,编译器不知道你的意图。 它可以做出最好的猜测,但C#并不是那种做出那种猜测的语言。 这也是你不能做像var = (int a) => a这样的事情的原因。

我确实认为编译器为Delegate d = (int a) => a;提供的错误消息Delegate d = (int a) => a; 很不清楚:

无法将lambda表达式转换为类型'System.Delegate',因为它不是委托类型

直觉上你会认为Delegate是一个委托类型,但事情并非如此。 :)

尝试这个:

void MyMethod(Action<int> func) { }

您需要强类型委托作为方法的参数。 其他调用失败的原因是因为C#编译器不允许您将lambda表达式传递给期望Object的方法,因为lambda表达式在所有情况下都不一定总是委托。 同样的规则适用于将lambda表达式作为Delegate传递。

当您将lambda传递给我上面显示的函数时,编译可以安全地假设您希望将lambda表达式转换为特定的委托类型并执行此操作。

它只是你需要明确地投下了委托对象编译器的性质Delegate路过时,它作为类型的参数Delegate 事实上,lambda表达式甚至进一步复杂化,因为在这种情况下它们不能隐式转换为委托。

你需要的是双重演员,因此:

MyMethod((Delegate)(Func<int, int>)((int a) => a));

这当然对应于方法签名:

void MyMethod(Delegate d);

根据您的具体情况,您可能希望定义一个类型为Func<int>的参数而不是Delegate (尽管我会犹豫添加一个重载,只是因为它增加了不必要的诚实复杂性)。

这种失败的原因与“object del =(int a)=> a”或甚至“var del =(int a)=> a”这样的表达式失败的原因相同。 您可能认为编译器可以找出lambda表达式的类型,因为您明确地给出了参数的类型,但即使知道表达式采用int并返回int,也可以转换许多委托类型至。 Func委托类型是最常用于泛型函数的类型,但这只是一种约定,编译器并不知道。

你需要做的是将lambda表达式转换为具体的委托类型,以便让编译器选择Delegate重载,使用普通的强制转换语法(Func)((int a)=> a),或者使用委托构造函数语法new Func((int a)=> a)。

此外,您通常不希望使用无类型的Delegate类,除非您需要根据它接受的参数数量调用不同的内容。 接受回调等事情的Func或Action几乎总是更好。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM