Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/282.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么C#编译器在使用LINQ方法Any()时会创建私有DisplayClass?我如何避免它?_C#_Performance_Linq_Instance_Any - Fatal编程技术网

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

为什么C#编译器在使用LINQ方法Any()时会创建私有DisplayClass?我如何避免它?,c#,performance,linq,instance,any,C#,Performance,Linq,Instance,Any,我有这个代码(整个代码并不重要,但可以在上看到): 例如,在反编译器(ILSpy)中打开代码后,我注意到c编译器新创建的类c#u DisplayClass0_0: 如果这段代码对系统的性能不是至关重要的,那么这对我来说不会是一个问题。此方法被调用数百万次,垃圾收集器正在清理这些c\uu DisplayClass0\u 0实例,这会降低性能: 使用Any方法时,如何避免创建此类(his实例及其垃圾收集)? 为什么C#编译器会创建这个类?我可以使用any()的任何替代方法吗?要理解“显示类”,必

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

例如,在反编译器(ILSpy)中打开代码后,我注意到c编译器新创建的类
c#u DisplayClass0_0

如果这段代码对系统的性能不是至关重要的,那么这对我来说不会是一个问题。此方法被调用数百万次,垃圾收集器正在清理这些
c\uu DisplayClass0\u 0
实例,这会降低性能:

使用
Any
方法时,如何避免创建此类(his实例及其垃圾收集)?

为什么C#编译器会创建这个类?我可以使用
any()
的任何替代方法吗?

要理解“显示类”,必须理解闭包。这里传递的lambda是一个闭包,一种特殊类型的方法,它神奇地将状态从它所在的方法的范围中拖出,并“围绕”它

……当然,除了没有魔法这回事。所有这些状态都必须实际存在于某个真实的地方,某个与闭包方法相关的地方,并且可以随时从闭包方法中获得。如果将状态与一个或多个方法直接关联,那么您将如何称呼编程模式

没错:上课。编译器将lambda转换为闭包类,然后在宿主方法内实例化该类,以便宿主方法可以访问该类中的状态

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

在使用Any方法时,如何避免创建此类(his实例及其垃圾收集)

为什么C#编译器会创建这个类?我可以使用任何()的替代方法吗

其他海报已经解释了为什么部分,因此更好的问题是如何避免创建结束?。答案很简单:如果lambda只使用传递的参数和/或常量,编译器将不会创建闭包。例如:

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

bool AnyOf(CardSuit suit) { return playerCards.Any(c => c.Suit == suit); }
第一个将不会创建闭包,而第二个将创建闭包

考虑到所有这些,并且假设您不想对/foreach
循环使用,您可以创建自己的扩展方法,类似于
System.Linq.Enumerable
中的扩展方法,但需要附加参数。对于这种特殊情况,类似这样的方法会起作用:

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;
    }
} 

它需要重写您的代码,以便为捕获的变量、其他玩家卡和王牌找到安全的归宿。将它们从局部变量转换为字段,以便在方法体之外保留它们的值。DisplayClass就是这样一个安全的家。不要在热路径上使用LINQ,这是Roslyn代码库的策略。我通常会避免推荐微优化,但如果此代码被运行数百万次,则重构此代码以优化其速度将是这里的解决方案。LINQ很慢。@DaveShaw reference?@DanielA.White--请参阅编码约定。“任何足够先进的技术都无法与magic区分开来。”-Arthur C.ClarkeHm,为什么不为参数或实例成员创建闭包?我知道这是不可能的。@usr它将创建一个静态/实例函数并绑定一个委托给它。不需要单独的类,因为整个状态由参数和/或
this
组成。好的,不需要类。没错。但该类对性能的影响为零。创建新的委托和闭包实例是非常昂贵的。我相信问题是关于性能的。他并不关心隐藏的类本身。@usr好吧,每次调用创建类实例肯定是额外的GC压力。此外,当lambda不使用实例成员时(如OP案例中),编译器将使用编译的委托生成一个静态字段(一次)
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());