简体   繁体   English

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

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

I have this code (the whole code is not important but can be seen on this link ): 我有这个代码(整个代码并不重要,但可以在这个链接上看到):

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

After opening the code in decompiler (ILSpy) for example I noticed the existence of newly created class <>c__DisplayClass0_0 by the C# compiler: 例如,在反编译器(ILSpy)中打开代码之后,我注意到C#编译器存在新创建的类<>c__DisplayClass0_0

在此输入图像描述

This wouldn't be a problem for me if this code wasn't critical for the performance of the system. 如果此代码对系统性能不重要,这对我来说不是问题。 This method is called millions of times and the garbage collector is cleaning these <>c__DisplayClass0_0 instances which slows down the performance: 这个方法被调用数百万次,垃圾收集器正在清理这些<>c__DisplayClass0_0实例,这会降低性能:

在此输入图像描述

How can I avoid creating this class (his instances and their garbage collecting) when using the Any method? 在使用Any方法时,如何避免创建此类(他的实例和垃圾收集)?

Why does the C# compiler create this class and is there any alternative of Any() I can use? 为什么C#编译器创建了这个类,我可以使用Any()替代方法吗?

To understand the "display class" you have to understand closures. 要理解“显示类”,您必须了解闭包。 The lambda you pass here is a closure , a special type of method that magically drags in state from the scope of the method it's in and "closes around" it. 你在这里传递的lambda是一个闭包 ,一种特殊类型的方法,它从它所处方法的范围中神奇地拖拽状态并“绕过”它。

...except of course that there's no such thing as magic. ......当然除了没有魔法这样的东西。 All that state has to actually live somewhere real, somewhere that's associated with the closure method and readily available from it. 所有这个状态实际上都必须存在于真实的某个地方,这个地方与封闭方法有关并且可以从中获得。 And what do you call the programming pattern where you associate state directly with one or more methods? 您将编程模式称为直接将状态与一个或多个方法关联的是什么?

That's right: classes. 那是对的: 上课。 The compiler transforms the lambda into a closure class, then instantiates the class inside the hosting method so the hosting method can access the state in the class. 编译器将lambda转换为闭包类,然后在托管方法中实例化类,以便托管方法可以访问类中的状态。

The only way to not have this happen is to not use closures. 不发生这种情况的唯一方法是不使用闭包。 If this is really impacting performance, use an old-school FOR loop instead of a LINQ expression. 如果这确实影响了性能,请使用旧式FOR循环而不是LINQ表达式。

How can I avoid creating this class (his instances and their garbage collecting) when using the Any method? 在使用Any方法时,如何避免创建此类(他的实例和垃圾收集)?

Why does the C# compiler creates this class and is there any alternative of Any() I can use? 为什么C#编译器会创建这个类,我可以使用Any()的替代方法吗?

Other posters already explained the why part, so the better question would be How can I avoid creation of a closure? 其他海报已经解释了原因部分,所以更好的问题是如何避免创建闭包? . And the answer is simple: if lambda is using only the passed parameters and/or constants, the compiler will not create a closure. 答案很简单:如果lambda 使用传递的参数和/或常量,编译器将不会创建闭包。 For instance: 例如:

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

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

The first will not create a closure while the second will. 第一个将不会创建一个闭包,而第二个将。

With all that in mind, and assuming you don't want to use for/foreach loops, you can create own extension methods similar to those in System.Linq.Enumerable but with additional parameters. 考虑到所有这些,并假设您不想使用for / foreach循环,您可以创建自己的扩展方法,类似于System.Linq.Enumerable的扩展方法,但具有其他参数。 For this particular case, something like this would work: 对于这种特殊情况,这样的事情会起作用:

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

and change the code in question to: 并将有问题的代码更改为:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 C#编译器是否将lambda表达式视为公共或私有方法? - Does the C# compiler treat a lambda expression as a public or private method? 我何时应该在c#中创建一个私有方法 - when should i create a private method in c# C#LINQ性能,如何避免它? - C# LINQ Performance, How can I avoid It? 为什么C#编译器不允许接口中的私有属性设置器? - Why C# compiler does not allows private property setters in interfaces? 为什么C#编译器认为我在使用可空的long时尝试使用sbyte重载? - Why does the C# compiler think I'm trying to use the sbyte overload when using nullable longs? 为什么此C#代码具有未声明的get主体构建? 以及如何使编译器对此产生错误? - Why does this C# code with an an undeclared get body build? And how can I make the compiler throw an error on this? 为什么C#编译器会对这个嵌套的LINQ查询感到厌烦? - Why does the C# compiler go mad on this nested LINQ query? 为什么 C# 编译器允许使用 Linq 而不是使用括号执行强制转换? - Why does the C# compiler allow a cast to be performed with Linq but not with parentheses? 为什么代码生成称为&lt;&gt; c__DisplayClass1的MSIL类 - Why Does Code Generate MSIL Class Called <>c__DisplayClass1 如何使用MethodInfo调用非静态的lambda方法(使用&lt;&gt; c__DisplayClass1) - How to invoke lambda method that is non-static using MethodInfo (uses <>c__DisplayClass1)
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM