I have got a question. See the two blocks of code. Isn't Where()
, OrderBy()
and Select()
from IEnumerable
Class supposed to take a delegate type, lambda expression or anonymous type as a parameter. If so, how did the QueryOverStringWithRawDelegate()
produce the same results as QueryOverStringsWithExtensionMethods()
?
void QueryOverStringsWithExtensionMethods()
{
// Assume we have an array of strings
string[] currentVideoGames = { "Morrowind", "Uncharted 2", "Fallout 3", "Daxter", "Bio Shock 4" };
IEnumerable<string> subset = currentVideoGames.Where(game => game.Contains(" ")).OrderBy(game => game).Select(delegate (string game) { return game; });
Console.WriteLine("Query Over Strings With Extension Method");
foreach (var s in subset)
{
Console.WriteLine("Items: {0}", s);
}
}
and
void QueryStringsWithRawDelegates()
{
// Assume we have an array of strings
string[] currentVideoGames = { "Morrowind", "Uncharted 2", "Fallout 3", "Daxter", "Bio Shock 4" };
var subset = currentVideoGames.Where(Filter).OrderBy(ProcessItems).Select(ProcessItems);
foreach (var s in subset)
{
Console.WriteLine("Items: {0}", s);
}
string ProcessItems(string game)
{
return game;
}
bool Filter(string game)
{
return game.Contains(" ");
}
}
Thank you for your help !
currentVideoGames.Where(Filter)
is simply shorthand for:
currentVideoGames.Where(new Func<string, bool>(Filter))
That is, the compiler sees that you've got a method which takes a delegate type Func<string, bool>
, it sees that you're giving it a method which has the signature bool Filter(string)
(strictly, a method group of one or more overloads, one of which has a signature that's close enough), and it automatically inserts the code to instantiate a new delegate instance.
This same language feature lets you write things like:
SomeEvent += Handler;
rather than:
SomeEvent += new EventHandler(Handler);
Similarly:
currentVideoGames.Where(game => game.Contains(" "))
is shorthand for:
currentVideoGames.Where(new Func<string, bool>(CompilerGeneratedFunction))
where CompilerGeneratedFunction
will look something like:
bool CompilerGeneratedFunction(string x)
{
return x.Contains(" ");
}
See this on SharpLab. It so happens that the compiler's put CompilerGeneratedFunction
(which it called <M>b__0_0
) in a new inner class, and it caches the Func<string, bool>
that it instantiates for performance reasons.