virtuales que programacion new modificador metodos clase anonima and c# performance linq instance any

que - ¿Por qué el compilador de C#crea DisplayClass privado cuando se usa el método Any() de LINQ y cómo puedo evitarlo?



que es override en programacion (2)

Tengo este código (el código completo no es importante, pero se puede ver en este enlace ):

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

Después de abrir el código en decompiler (ILSpy), por ejemplo, noté la existencia de una clase recién creada <>c__DisplayClass0_0 por el compilador C #:

Esto no sería un problema para mí si este código no fuera crítico para el rendimiento del sistema. Este método se llama millones de veces y el recolector de basura está limpiando estas instancias <>c__DisplayClass0_0 , lo que ralentiza el rendimiento:

¿Cómo puedo evitar crear esta clase (sus instancias y su recolección de basura) cuando utilizo el método Any ?

¿Por qué el compilador de C # crea esta clase y hay alguna alternativa de Any() que pueda usar?


¿Cómo puedo evitar crear esta clase (sus instancias y su recolección de basura) cuando utilizo el método Any?

¿Por qué el compilador de C # crea esta clase y hay alguna alternativa de Any () que pueda usar?

Otros carteles ya explicaron la parte de por qué , entonces la mejor pregunta sería: ¿Cómo puedo evitar la creación de un cierre? . Y la respuesta es simple: si lambda está usando solo los parámetros y / o constantes pasados, el compilador no creará un cierre. Por ejemplo:

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

El primero no creará un cierre mientras que el segundo lo hará.

Con todo eso en mente, y suponiendo que no desea utilizar para / foreach loops, puede crear métodos de extensión propios similares a los de System.Linq.Enumerable pero con parámetros adicionales. Para este caso particular, algo como esto funcionaría:

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

y cambiar el código en cuestión a:

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


Para entender la "clase de visualización" tienes que entender los cierres. La lambda que se pasa aquí es un cierre , un tipo especial de método que se arrastra mágicamente en el estado del alcance del método en el que se encuentra y lo "cierra".

... excepto, por supuesto, que no existe la magia. Todo ese estado tiene que vivir realmente en un lugar real, en algún lugar que esté asociado con el método de cierre y que esté disponible de inmediato. ¿Y cómo llama al patrón de programación donde asocia el estado directamente con uno o más métodos?

Así es: las clases. El compilador transforma la lambda en una clase de cierre, luego crea una instancia de la clase dentro del método de alojamiento para que el método de alojamiento pueda acceder al estado de la clase.

La única forma de que esto no suceda es no usar cierres. Si esto realmente afecta el rendimiento, use un bucle FOR vieja escuela en lugar de una expresión LINQ.