【问题标题】:C# Action lambda limitationC# 动作 lambda 限制
【发布时间】:2008-10-31 17:19:45
【问题描述】:

为什么这个 lambda 表达式不能编译?

Action a = () => throw new InvalidOperationException();

猜想很好,但我非常感谢参考 C# 语言规范或其他文档。

是的,我知道以下是有效的并且可以编译:

Action a = () => { throw new InvalidOperationException(); };

this blog post 上描述了我会使用此类内容的上下文。

【问题讨论】:

  • 哦,有机会得到一个被接受的答案:) 打破大枪(Skeet 先生)为什么不呢! :) :)
  • 哈哈。相信我,我没什么特别的。在 7 英寸的屏幕上浏览 C# 规范也不是一件容易的事;)

标签: c# compiler-construction lambda


【解决方案1】:

嗯。我有答案,但不是很好。

我不相信有“投掷”表达式。有一个 throw 语句,但不仅仅是一个表达式。将此与“Console.WriteLine()”进行比较,后者是一个 void 类型的方法调用表达式。

作为并行,您不能将 switch 语句或 if 语句等作为 lambda 的主体。你只能有一个表达式或一个块(第 7.14 节)。

这有什么帮助吗?

【讨论】:

  • 这就是我几分钟前所说的。你只需要问自己:“一个陈述的评价是什么?”答案是什么。
  • 好吧,对 Console.WriteLine 的调用也不会计算出任何结果,除非你算上“void”......但是是的,我们当然是按照同样的思路思考的,因此我的 +1你的答案:)
  • 这很有帮助。我仍然想知道为什么分配给闭包是有效的,因为我将“num = 0”作为语句阅读。
  • Console.WriteLine 确实匹配返回类型 :)
  • "num = 0" 是一个赋值表达式。 “数=0;”是一个声明。
【解决方案2】:

这是我的看法:

throw 是语句,而不是表达式。

以及参考:

12.3.3.11 抛出语句

对于形式的语句stmt

throw expr;

v的确定赋值状态 expr 开头是一样的 作为 v 的明确赋值状态 在 stmt 的开头。

为了解释本质,也许人们应该考虑一下表达式在 C# lambda 构造中的含义。它只是语法糖:

delegate () { return XXX; }

XXX 是一个表达式

【讨论】:

  • 但你永远不能说 return Console.WriteLine("something")
【解决方案3】:

您不能从非作用域的 lambda 返回或抛出。

这样想...如果您不提供 {},编译器会确定您的隐式返回值是什么。当您在 lambda 中 throw 时,没有返回值。你甚至没有返回void。为什么编译器团队不处理这种情况,我不知道。

【讨论】:

    【解决方案4】:

    我能找到的所有参考资料,都来自这里:

    http://msdn.microsoft.com/en-us/library/ms364047(VS.80).aspx#cs3spec_topic4

    表明你有两个选择:

    Action a = () => { throw new InvalidOperationException(); };
    

    Action a = () => throw new InvalidOperationException()
    

    注意缺少的 ;最后。是的,这对我来说也没有意义。他们在规范中给出的例子是:

    x => x + 1                     // Implicitly typed, expression body
    x => { return x + 1; }         // Implicitly typed, statement body
    (int x) => x + 1               // Explicitly typed, expression body
    (int x) => { return x + 1; }   // Explicitly typed, statement body
    (x, y) => x * y               // Multiple parameters
    () => Console.WriteLine()      // No parameters
    

    不知道这有多大帮助 - 我不知道你在什么上下文中使用它,而不是放一个 ;最后在 C# 中没有意义

    不同之处可能在于它是一个表达式主体——而不是一个语句——如果它没有 {}。这意味着你的 throw 在那里无效,因为它是一个语句,而不是一个表达式!

    【讨论】:

    • 没有分号在 lambda 主体的上下文中是有意义的,但不是作为您分配给操作的语句。在jacobcarpenter.wordpress.com/2008/10/06/… 中提到了我将使用它的上下文
    • 我可以向你保证 Action a = () => throw new InvalidOperationException() 不会编译。
    • 编译器仍然需要一个 ;在行尾。
    【解决方案5】:

    没有什么大惊喜。 Lambda 表达式是 函数式 编程的一个方面。异常是过程编程的一个方面。两种编程风格之间的 C# 网格并不完美。

    【讨论】:

    • 不,这里的问题不是副作用方面。即使没有副作用,你也不能有一个“if”语句,但是你可以有一个赋值表达式,它是一个副作用。这是语句/表达式的区别。
    • 对。在纯粹的函数式编程中,这是 lambda 表达式所要使用的模型,只有表达式,没有语句(语句是用 monadic 表达式模仿的)。让基于语句的语言与纯表达式很好地配合有点棘手。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-17
    • 2018-11-30
    • 2014-12-28
    • 1970-01-01
    • 2017-03-09
    • 1970-01-01
    相关资源
    最近更新 更多