5

I have just come across the following code (.NET 3.5), which doesn't look like it should compile to me, but it does, and works fine:

bool b = selectedTables.Any(table1.IsChildOf));

Table.IsChildOf is actually a method with following signature:

public bool IsChildOf(Table otherTable)

Am I right in thinking this is equivalent to:

bool b = selectedTables.Any(a => table1.IsChildOf(a));

and if so, what is the proper term for this?

tomfanning
  • 9,552
  • 4
  • 50
  • 78
  • it could be connected to this: http://stackoverflow.com/questions/5245012/simple-linq-expression-wont-compile/5245066#5245066 – xanatos Mar 10 '11 at 10:46

3 Answers3

13

This is a method group conversion, and it's been available since C# 2. As a simpler example, consider:

public void Foo()
{
}

...

ThreadStart x = Foo;
ThreadStart y = new ThreadStart(Foo); // Equivalent code

Note that this is not quite the same as the lambda expression version, which will capture the variable table1, and generate a new class with a method in which just calls IsChildOf. For Any that isn't important, but the difference would be important for Where:

var usingMethodGroup = selectedTables.Where(table1.IsChildOf);
var usingLambda = selectedTables.Where(x => table1.IsChildOf(x));
table1 = null;

// Fine: the *value* of `table1` was used to create the delegate
Console.WriteLine(usingMethodGroup.Count());

// Bang! The lambda expression will try to call IsChildOf on a null reference
Console.WriteLine(usingLambda.Count());
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • do you mean that the first one is a closure, while the lambda is not? – Can Gencer Mar 10 '11 at 10:57
  • 1
    @Can: Other way round - the lambda is a closure, capturing table1. – Jon Skeet Mar 10 '11 at 10:58
  • Yes, I understand now. These things easily get confusing:) This will also be a closure, right? selectedTables.Where(delegate(Table table) { return table1.IsChildOf(table); }); – Can Gencer Mar 10 '11 at 11:10
  • 1
    @Can: Yes - that's an *anonymous method* from C# 2. Lambda expressions in C# 3 have almost completely replaced anonymous methods. – Jon Skeet Mar 10 '11 at 12:10
5

The expression table1.IsChildOf is called a method group.

You are right in that it is equivalent, and indeed this is syntactic sugar.

Community
  • 1
  • 1
Jon
  • 428,835
  • 81
  • 738
  • 806
  • 2
    It's not really equivalent - for Any the results will be the same (unless there's another thread involved changing the value of table1) but in general there can be a significant difference. See my answer for an example. – Jon Skeet Mar 10 '11 at 10:47
  • @Jon: You are certainly right, and your explanation of what goes on behind the scenes is very valuable. But in my defense, changing the value of `table1` before the query is enumerated is something you don't see every day. – Jon Mar 10 '11 at 10:57
  • @Jon: True, but given the lazy nature of many LINQ operators, I think it's important to understand how capturing works (vs method group conversion). – Jon Skeet Mar 10 '11 at 10:59
  • @Jon: Agreed. Now if only we could get everyone to understand closure... ;) – Jon Mar 10 '11 at 11:01
  • 3
    @Jon and @Jon, Resharper used to have a bug that fell into the exact pitfal Mr Skeet is pointing out. `Event1 += (o, e) => Event2(o, e);` will "chain" events, causing `Event2` to fire whenever `Event1` fires. But Resharper would happily suggest the alternative `Event1 += Event2`, which is totally different: it immediately copies any handlers *currently* in `Event2` on to `Event1`'s list. Typically the result is that the events don't get passed on as expected (because `Event2` might still be an empty list at the time when the copy occurs). – Daniel Earwicker Mar 10 '11 at 11:13
  • Er, when I say "exact", maybe "analogous" would be more accurate. – Daniel Earwicker Mar 10 '11 at 11:13
2

It's called a method group. Resharper encourages this kind of code.

ilivewithian
  • 19,476
  • 19
  • 103
  • 165