Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can `s => x.Append(s)` can be passed as an Action<string> but `x.Append` can't?

Tags:

c#

.net

lambda

I noticed something strange when trying to pass a StringBuilder's Append method to a function that took an Action<string>.

public void DoStuff(Action<string> handler)
{
    // Do stuff, call handler("data");
}

For testing purposes, I just want to write the data into a StringBuilder, so I tried to call it like this:

var output = new StringBuilder();
DoStuff(output.Append);

However, this gives a compile error, because the Append method does not match the required signature (it returns a reference back to the StringBuilder, not void as my method wants):

'System.Text.StringBuilder System.Text.StringBuilder.Append(string)' has the wrong return type

Without thinking, I changed the code to this:

var output = new StringBuilder();
DoStuff(s => output.Append(s));

This compiled fine.

Then I got confused; realising that s => output.Append(s) should also return the StringBuilder, aren't they the same?

So, why does this work? Why can s => output.Append(s) have the return value discarded silently, yet output.Append cannot?

like image 937
Danny Tuppeny Avatar asked Jun 12 '14 18:06

Danny Tuppeny


1 Answers

s => output.Append(s) creates a new lambda expression, which is inferred (from the context) to have a return type of void.
Therefore, the value of the expression body is ignored.
This is compiled to a separate method that calls Append() and returns void (this exactly matching the delegate)

In contrast, when you attempt to convert a method group to a delegate, the conversion must match exactly.

The spec (§6.5) says:

Specifically, an anonymous function F is compatible with a delegate type D provided:

  • If the body of F is an expression, and either D has a void return type or F is async and D has the return type Task, then when each parameter of F is given the type of the corresponding parameter in D, the body of F is a valid expression (wrt §7) that would be permitted as a statement-expression (§8.6).
like image 77
SLaks Avatar answered Nov 15 '22 19:11

SLaks