为什么不能使用内联匿名 lambda 或委托?
我希望我的问题标题措辞恰当。
在 c# 中,我可以使用 lambda(作为委托)或较旧的委托语法来执行此操作:
Func<string> fnHello = () => "hello";
Console.WriteLine(fnHello());
Func<string> fnHello2 = delegate()
{
return "hello 2";
};
Console.WriteLine(fnHello2());
那么为什么我不能“内联”lambda 或委托主体,并避免在命名变量中捕获它(使其匿名)?
// Inline anonymous lambda not allowed
Console.WriteLine(
(() => "hello inline lambda")()
);
// Inline anonymous delegate not allowed
Console.WriteLine(
(delegate() { return "hello inline delegate"; })()
);
在 javascript 中工作的一个示例(仅用于比较)是:
alert(
(function(){ return "hello inline anonymous function from javascript"; })()
);
它会产生预期的警报框。
更新: 如果您进行适当的转换,您似乎可以在 C# 中拥有内联匿名 lambda,但是 () 的数量开始使其难以控制。
// Inline anonymous lambda with appropriate cast IS allowed
Console.WriteLine(
((Func<string>)(() => "hello inline anonymous lambda"))()
);
也许编译器无法推断匿名委托的 sig 来知道您要调用哪个 Console.WriteLine() ?有谁知道为什么需要这个特定的演员阵容?
I hope I worded the title of my question appropriately.
In c# I can use lambdas (as delegates), or the older delegate syntax to do this:
Func<string> fnHello = () => "hello";
Console.WriteLine(fnHello());
Func<string> fnHello2 = delegate()
{
return "hello 2";
};
Console.WriteLine(fnHello2());
So why can't I "inline" the lambda or the delegate body, and avoid capturing it in a named variable (making it anonymous)?
// Inline anonymous lambda not allowed
Console.WriteLine(
(() => "hello inline lambda")()
);
// Inline anonymous delegate not allowed
Console.WriteLine(
(delegate() { return "hello inline delegate"; })()
);
An example that works in javascript (just for comparison) is:
alert(
(function(){ return "hello inline anonymous function from javascript"; })()
);
Which produces the expected alert box.
UPDATE:
It seems you can have an inline anonymous lambda in C#, if you cast appropriately, but the amount of ()'s starts to make it unruly.
// Inline anonymous lambda with appropriate cast IS allowed
Console.WriteLine(
((Func<string>)(() => "hello inline anonymous lambda"))()
);
Perhaps the compiler can't infer the sig of the anonymous delegate to know which Console.WriteLine() you're trying to call? Does anyone know why this specific cast is required?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
C# 中的 Lambda 没有类型,除非在将它们转换为委托或表达式类型的上下文中使用它们。
这就是为什么您无法执行以下操作:
您可能会喜欢 Eric Lippert 的 Lambda 表达式与匿名方法系列
Lambdas in C# do not have types, until they are used in a context that casts them to a delegate or Expression type.
That's why you cannot do the following:
You might enjoy Eric Lippert's Series on Lambda Expressions vs Anonymous Methods
如果你给它一个类型转换,它似乎可以工作:
它没用吗?不完全是。如下所示:
现在考虑一下:
它有点难看,但很紧凑。
It seems to work if you give it a type cast:
Is it useless? Not entirely. Take the below:
Now consider this:
It's a little ugly, but it is compact.
当您编写
Func; = ...
,编译器知道它必须创建一个Func
类型的对象。但是,当您内联编写该委托时,编译器不知道它必须创建哪种类型的对象。说了以上,可以得出一个明显的结论:显式告诉编译器类型即可!
更新
好吧,当我写答案时,你更新了你的帖子。
我相信我上面的回答已经回答了“为什么需要这种特定类型”的问题。重申一下:因为编译器不知道要创建哪种类型的对象。
现在详细说明一下“编译器无法推断匿名委托的 sig”部分。你看,这与 JavaScript 不同。在 C# 中,没有通用的“函数”(或“方法”)类型。每个委托必须具有显式指定的签名和类型名称。当您创建委托时,编译器必须知道什么类型。
现在,我可以明白您如何暗示编译器可以动态构造委托类型,就像处理匿名对象类型一样(又名
new { a = 1, b = "xyz" }
)。但想一想:无论如何,这样的委托可能没有用处。我的意思是,您不能将其传递给另一个方法,因为该方法必须首先声明其参数的类型。而且你不能用它来创建一个事件,因为你必须有一个命名类型。类似这样的事情...
When you write
Func<string> = ...
, the compiler knows that it has to create an object of typeFunc<string>
. But when you write that delegate inline, the compiler doesn't know object of which type it has to create.Having said the above, an obvious conclusion can be drawn: just tell the compiler the type explicitly!
UPDATE
Ok, while I was writing the answer, you updated your post.
I believe my answer above already answers the question "why this specific type is required". To reiterate: because the compiler doesn't know object of which type to create.
Now to elaborate a bit on the "the compiler can't infer the sig of the anonymous delegate" part. You see, it's not like in JavaScript. In C#, there's no generic "function" (or "method") type. Each delegate must have an explicitly specified signature and type name. And when you're creating a delegate, the compiler must know what type.
Now, I can see how you may imply that the compiler could just construct a delegate type on the fly, like it does with anonymous object types (aka
new { a = 1, b = "xyz" }
). But think about it for a moment: there would be probably no use for such delegate anyway. I mean, you can't pass it to another method, because that method has to declare types of it's arguments first. And you can't make an event out of it, because, again, you must have a named type.Something like that...
您可以对接受委托参数的方法使用内联 lambda 表达式。
然而,有一个小问题 - 如果参数被输入为基本 Delegate 类型,则需要将其显式转换为 Delegate 的特定派生(例如 Action);否则编译器会抱怨。
类似问题:
Invoke 调用中的匿名方法
匿名方法和委托
You can use inline lambda expressions for methods that take in a Delegate parameter.
However there is a slight catch - if the parameter is typed as the base Delegate type, you'd need to explicitly cast it to a specific derivation of Delegate (say Action) ; else the compiler would complain.
Similar questions:
Anonymous method in Invoke call
Anonymous methods and delegates