为什么不能使用内联匿名 lambda 或委托?

发布于 2024-08-29 10:21:56 字数 1088 浏览 5 评论 0原文

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

在 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

似狗非友 2024-09-05 10:21:56

C# 中的 Lambda 没有类型,除非在将它们转换为委托或表达式类型的上下文中使用它们。

这就是为什么您无法执行以下操作

var x = () => "some 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:

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

You might enjoy Eric Lippert's Series on Lambda Expressions vs Anonymous Methods

水晶透心 2024-09-05 10:21:56

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

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

它有点难看,但很紧凑。

It seems to work if you give it a type cast:

String s = ((Func<String>) (() => "hello inline lambda"))();

Is it useless? Not entirely. Take the below:

String s;
{
    Object o = MightBeNull();
    s = o == null ? "Default value" : o.ToString();
}

Now consider this:

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

It's a little ugly, but it is compact.

北音执念 2024-09-05 10:21:56

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

说了以上,可以得出一个明显的结论:显式告诉编译器类型即可!

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

更新

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

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

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

类似这样的事情...

When you write Func<string> = ..., the compiler knows that it has to create an object of type Func<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!

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

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...

め可乐爱微笑 2024-09-05 10:21:56

您可以对接受委托参数的方法使用内联 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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文