我希望我的问题标题措辞恰当。
在 c# 中,我可以使用 lambdas(作为委托)或旧的委托语法来执行此操作:
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"; })()
);
产生预期的警告框。
更新: 看起来你 can 在 C# 中有一个内联匿名 lambda,如果你适当地转换,但是 () 的数量开始让它变得不守规矩。
// Inline anonymous lambda with appropriate cast IS allowed
Console.WriteLine(
((Func<string>)(() => "hello inline anonymous lambda"))()
);
也许编译器无法推断匿名委托的签名来知道您要调用哪个 Console.WriteLine()?有谁知道为什么需要这个特定演员表?
C# 中的 Lambda 没有类型,除非在将它们转换为委托或表达式类型的上下文中使用它们。
这就是为什么你不能做以下事情:
var x = () => "some lambda";
您可能会喜欢 Eric Lippert 关于 Lambda 表达式与匿名方法的系列
如果你给它一个类型转换,它似乎可以工作:
String s = ((Func<String>) (() => "hello inline lambda"))();
没用吗?不是完全。采取以下:
String s;
{
Object o = MightBeNull();
s = o == null ? "Default value" : o.ToString();
}
现在考虑一下:
String S = ((Func<Object,String>)(o => o == null ? "Default value" : o.ToString())
)(MightBeNull());
有点丑,但是很紧凑。
当你写
Func<string> = ...
时,编译器知道它必须创建一个Func<string>
类型的对象。但是,当您内联编写该委托时,编译器不知道它必须创建哪种类型的对象。
综上所述,可以得出一个显而易见的结论:明确告诉编译器类型即可!
Console.WriteLine( new Func<string>( () => "Hello" )() );
更新
好的,在我写答案的时候,你更新了你的帖子。 我相信我上面的回答已经回答了“为什么需要这种特定类型”的问题。重申一下:因为编译器不知道要创建哪种类型的对象。
现在详细说明“编译器无法推断匿名委托的签名”部分。你看,它不像在 JavaScript 中那样。在 C# 中,没有通用的“函数”(或“方法”)类型。每个委托都必须具有明确指定的签名和类型名称。当你创建一个委托时,编译器必须知道什么类型。
现在,我可以理解您是如何暗示编译器可以即时构造一个委托类型,就像它对匿名对象类型所做的那样(又名
new { a = 1, b = "xyz" }
)。但是想一想:无论如何,这样的委托可能没有用。我的意思是,您不能将它传递给另一个方法,因为该方法必须首先声明其参数的类型。而且你不能用它来做一个事件,因为,同样,你必须有一个命名类型。
类似的东西...
您可以对采用委托参数的方法使用内联 lambda 表达式。
然而,有一个小问题——如果参数被键入为基本委托类型,则需要将其显式转换为委托的特定派生(例如 Action);否则编译器会抱怨。
类似问题:
Invoke调用中的匿名方法
匿名方法和委托