c#: Enumerable Class 中的 Where()、OrderBy() 和 Select() 不应该采用委托类型、lambda 表达式或匿名类型作为参数

c#: Isn't Where(), OrderBy() and Select() from Enumerable Class supposed to take a delegate type, lambda expression or anonymous type as a parameter

我有一个问题。查看两个代码块。来自 IEnumerable Class 的 Where()OrderBy()Select() 不应该采用委托类型、lambda 表达式或匿名类型作为参数。如果是这样,QueryOverStringWithRawDelegate() 是如何产生与 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);
    }
}

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(" ");
    }
}

感谢您的帮助!

不,正如您所观察到的,这不是错误。编译器会将具有适当签名的方法组翻译成相应的 Func<> 类型。

currentVideoGames.Where(Filter)

只是 shorthand 用于:

currentVideoGames.Where(new Func<string, bool>(Filter))

也就是说,编译器看到你有一个采用委托类型 Func<string, bool> 的方法,它看到你给它一个具有签名 bool Filter(string) 的方法(严格,一个或多个重载的方法组,其中一个具有足够接近的签名),它会自动插入代码以实例化一个新的委托实例。

这种相同的语言功能让您可以编写如下内容:

SomeEvent += Handler;

而不是:

SomeEvent += new EventHandler(Handler);

See this on SharpLab.


同样:

currentVideoGames.Where(game => game.Contains(" "))

是 shorthand 为:

currentVideoGames.Where(new Func<string, bool>(CompilerGeneratedFunction))

其中 CompilerGeneratedFunction 看起来像:

bool CompilerGeneratedFunction(string x)
{
    return x.Contains(" ");
}

See this on SharpLab。碰巧编译器将 CompilerGeneratedFunction(它称为 <M>b__0_0)放在一个新的内部 class 中,并缓存它出于性能原因实例化的 Func<string, bool>