为什么c#不能使用内联匿名lambdas或委托?

Sam*_*ham 27 c# lambda anonymous-methods inline-method

我希望我能恰当地提出问题的标题.

在c#中,我可以使用lambdas(作为委托),或者使用较旧的委托语法来执行此操作:

Func<string> fnHello = () => "hello";
Console.WriteLine(fnHello());

Func<string> fnHello2 = delegate()
{
    return "hello 2";
};
Console.WriteLine(fnHello2());
Run Code Online (Sandbox Code Playgroud)

那么为什么我不能"内联"lambda或委托体,并避免在命名变量中捕获它(使其匿名)?

// Inline anonymous lambda not allowed
Console.WriteLine(
    (() => "hello inline lambda")()
);

// Inline anonymous delegate not allowed
Console.WriteLine(
    (delegate() { return "hello inline delegate"; })()
);
Run Code Online (Sandbox Code Playgroud)

在javascript中工作的示例(仅用于比较)是:

alert(
    (function(){ return "hello inline anonymous function from javascript"; })()
);
Run Code Online (Sandbox Code Playgroud)

这会产生预期的警报框.

更新:看起来你可以在C#中使用内联匿名lambda,如果你适当地进行转换,但是()的数量开始让它变得难以驾驭.

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

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

Bri*_*ian 22

C#中的Lambdas没有类型,直到它们被用于将它们转换为委托或表达式类型的上下文中.这就是你不能说的原因

var x = () => "some lambda";
Run Code Online (Sandbox Code Playgroud)

你可能会喜欢

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

  • +1。有关 C# 中 lambda 的重要基本概念。 (2认同)
  • 这可能会在 C# 10 中发生变化 https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-10.0/lambda-improvements (2认同)

小智 15

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

String s = ((Func<String>) (() => "hello inline lambda"))();
Run Code Online (Sandbox Code Playgroud)

它没用吗?不是完全.拿下面的话:

String s;
{
    Object o = MightBeNull();
    s = o == null ? "Default value" : o.ToString();
}
Run Code Online (Sandbox Code Playgroud)

现在考虑一下:

String S = ((Func<Object,String>)(o => o == null ? "Default value" : o.ToString())
    )(MightBeNull());
Run Code Online (Sandbox Code Playgroud)

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


Fyo*_*kin 9

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

如上所述,可以得出一个明显的结论:只需明确地告诉编译器类型!

Console.WriteLine( new Func<string>( () => "Hello" )() );
Run Code Online (Sandbox Code Playgroud)

UPDATE

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

现在详细阐述一下" 编译器无法推断匿名委托的sig "部分.你看,它不像在JavaScript中.在C#中,没有通用的"函数"(或"方法")类型.每个代理必须具有明确指定的签名和类型名称.当您创建委托时,编译器必须知道什么类型.

现在,我可以看到你如何暗示编译器可以动态地构造一个委托类型,就像它与匿名对象类型(aka new { a = 1, b = "xyz" })一样.但想一想:无论如何,这样的代表可能没用.我的意思是,你不能将它传递给另一个方法,因为该方法必须首先声明它的参数的类型.而且你可以用它来制作一个事件,因为你必须再次拥有一个命名类型.

这样的东西......