为什么 C# 编译器在使用 LINQ 方法 Any() 时创建私有 DisplayClass,我该如何避免?

Why does C# compiler create private DisplayClass when using LINQ method Any() and how can I avoid it?

我有这段代码(整个代码不重要但可以在this link上看到):

internal static class PlayCardActionValidator
{
    public static bool CanPlayCard(...)
    {
        // ...
        var hasBigger =
            playerCards.Any(
                c => c.Suit == otherPlayerCard.Suit
                     && c.GetValue() > otherPlayerCard.GetValue());
        // ...
    }
}

例如,在反编译器 (ILSpy) 中打开代码后,我注意到 C# 编译器存在新创建的 class <>c__DisplayClass0_0

如果这段代码对系统的性能不是很重要的话,这对我来说不是问题。此方法被调用了数百万次,垃圾收集器正在清理这些 <>c__DisplayClass0_0 个实例,这会降低性能:

如何在使用 Any 方法时避免创建此 class(他的实例及其垃圾收集)?

为什么 C# 编译器创建这个 class 并且我可以使用 Any() 的任何替代方法?

要理解 "display class" 你必须理解闭包。您在此处传递的 lambda 是一个 闭包 ,一种特殊类型的方法,可以神奇地将状态从它所在的方法的范围拖入 "closes around" 它。

...当然除了没有魔法这样的东西。所有这些状态实际上都必须存在于真实的某个地方,某个与闭包方法相关联并且可以从中轻松获得的地方。您将状态直接与一种或多种方法相关联的编程模式称为什么?

没错:classes. 编译器将 lambda 转换为闭包 class,然后实例化托管内部的 class方法,以便托管方法可以访问 class.

中的状态

避免这种情况发生的唯一方法是不使用闭包。如果这确实会影响性能,请使用老式 FOR 循环而不是 LINQ 表达式。

How can I avoid creating this class (his instances and their garbage collecting) when using the Any method?

Why does the C# compiler creates this class and is there any alternative of Any() I can use?

其他发帖人已经解释了为什么 部分,所以更好的问题是如何避免创建闭包?。答案很简单:如果 lambda 使用 传递的参数 and/or 常量,编译器将不会创建闭包。例如:

bool AnyClub() { return playerCards.Any(c => c.Suit == CardSuit.Club); }

bool AnyOf(CardSuit suit) { return playerCards.Any(c => c.Suit == suit); }

第一个不会创建闭包,而第二个会。

考虑到所有这些,假设您不想使用 for/foreach 循环,您可以创建自己的扩展方法,类似于 [=13] =] 但带有附加参数。对于这种特殊情况,类似这样的事情会起作用:

public static class Extensions
{
    public static bool Any<T, TArg>(this IEnumerable<T> source, TArg arg, Func<T, TArg, bool> predicate)
    {
        foreach (var item in source)
            if (predicate(item, arg)) return true;
        return false;
    }
} 

并将有问题的代码更改为:

var hasBigger =
    playerCards.Any(otherPlayerCard, 
        (c, opc) => c.Suit == opc.Suit
             && c.GetValue() > opc.GetValue());