为什么`s =&gt; x.Append(s)`可以作为Action <string>传递但是`x.Append`不能?</string>

时间:2014-06-12 18:05:28

标签: c# .net lambda

我尝试将StringBuilder的{​​{1}}方法传递给一个Append的函数时发现了一些奇怪的事情。

Action<string>

出于测试目的,我只想将数据写入public void DoStuff(Action<string> handler) { // Do stuff, call handler("data"); } ,所以我试着这样称呼它:

StringBuilder

但是,这会产生编译错误,因为var output = new StringBuilder(); DoStuff(output.Append); 方法与所需的签名不匹配(它返回一个引用回Append,而不是我的方法想要的void):

  

'System.Text.StringBuilder System.Text.StringBuilder.Append(string)'的返回类型错误

我不假思索地将代码更改为:

StringBuilder

此编译罚款。

然后我感到困惑;意识到var output = new StringBuilder(); DoStuff(s => output.Append(s)); 也应该返回s => output.Append(s),它们不一样吗?

那么,为什么这有效呢?为什么StringBuilder可以静默丢弃返回值,但s => output.Append(s)不能?

1 个答案:

答案 0 :(得分:20)

s => output.Append(s)创建一个新的lambda表达式,该表达式(从上下文中推断)返回类型为void
因此,忽略表达式主体的值 这被编译为一个单独的方法,该方法调用Append()并返回void(这与委托完全匹配)

相反,当您尝试将方法组转换为委托时,转换必须完全匹配。

规范(§6.5)说:

  

具体来说,匿名函数F与提供的代理类型D兼容:

     
      
  • 如果F的主体是表达式,并且D具有void返回类型或者F是异步而D具有返回类型Task,那么当F的每个参数被赋予D中相应参数的类型时, F的主体是一个有效的表达式(wrt§7),它将被允许作为语句表达式(§8.6)。
  •