31

我希望我的问题标题措辞恰当。

在 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"; })()
);

这会产生预期的警报框。

更新:如果你适当地转换,你似乎可以在 C# 中使用内联匿名 lambda,但是 () 的数量开始使它变得不守规矩。

// Inline anonymous lambda with appropriate cast IS allowed
Console.WriteLine(
    ((Func<string>)(() => "hello inline anonymous lambda"))()
);

也许编译器无法推断匿名委托的信号来知道您要调用哪个 Console.WriteLine() ?有谁知道为什么需要这个特定的演员表?

4

4 回答 4

25

C# 中的 Lambda 没有类型,除非在将它们强制转换为委托或表达式类型的上下文中使用它们。这就是为什么你不能说

var x = () => "some lambda";

你可能会喜欢

http://blogs.msdn.com/ericlippert/archive/2007/01/11/lambda-expressions-vs-anonymous-methods-part-two.aspx

http://blogs.msdn.com/ericlippert/archive/2007/01/12/lambda-expressions-vs-anonymous-methods-part-three.aspx

于 2010-04-22T02:51:11.230 回答
16

如果你给它一个类型转换,它似乎工作:

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());

它有点难看,但它很紧凑。

于 2012-11-14T14:29:50.093 回答
9

当您编写Func<string> = ...时,编译器知道它必须创建一个类型的对象Func<string>。但是当您内联编写该委托时,编译器不知道它必须创建哪种类型的对象。

说了这么多,可以得出一个明显的结论:只要明确告诉编译器类型!

Console.WriteLine( new Func<string>( () => "Hello" )() );

更新

好的,当我写答案时,你更新了你的帖子。我相信我上面的回答已经回答了“为什么需要这种特定类型”的问题。重申一下:因为编译器不知道要创建哪种类型的对象。

现在详细说明“编译器无法推断匿名委托的信号”部分。你看,它不像在 JavaScript 中。在 C# 中,没有通用的“函数”(或“方法”)类型。每个委托都必须具有明确指定的签名和类型名称。当你创建一个委托时,编译器必须知道什么类型。

现在,我可以看到您如何暗示编译器可以即时构造一个委托类型,就像它对匿名对象类型(又名new { a = 1, b = "xyz" })所做的那样。但是想一想:无论如何,这样的代表可能没有用。我的意思是,您不能将它传递给另一个方法,因为该方法必须首先声明其参数的类型。你可以用它来做一个事件,因为,同样,你必须有一个命名的类型。

那样的东西...

于 2010-04-22T03:10:09.417 回答
2

您可以对采用 Delegate 参数的方法使用内联 lambda 表达式。

但是有一个小问题 - 如果参数被键入为基本 Delegate 类型,则需要将其显式转换为 Delegate 的特定派生(例如 Action);否则编译器会抱怨。

类似问题:
Invoke 中的匿名方法调用
匿名方法和委托

于 2010-04-22T03:06:36.683 回答