чайников - методы linq c#




Почему компилятор C#создает частный DisplayClass при использовании метода LINQ Any() и как его избежать? (2)

У меня этот код (весь код не важен, но можно увидеть по этой ссылке ):

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

После открытия кода в декомпиляторе (ILSpy), например, я заметил существование только что созданного класса <>c__DisplayClass0_0 компилятором C #:

Для меня это не проблема, если бы этот код не был критическим для производительности системы. Этот метод называется миллионы раз, и сборщик мусора <>c__DisplayClass0_0 экземпляры <>c__DisplayClass0_0 что замедляет производительность:

Как я могу избежать создания этого класса (его экземпляры и сбор мусора) при использовании метода Any ?

Почему компилятор C # создает этот класс и есть ли альтернатива Any() я могу использовать?


Как я могу избежать создания этого класса (его экземпляры и сбор мусора) при использовании метода Any?

Почему компилятор C # создает этот класс и есть ли альтернатива Any (), которую я могу использовать?

Другие плакаты уже объяснили причину , поэтому лучший вопрос: как я могу избежать создания закрытия? , И ответ прост: если лямбда использует только переданные параметры и / или константы, компилятор не создаст закрытие. Например:

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

и измените соответствующий код на:

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

Чтобы понять «класс отображения», вы должны понимать закрытие. Лямбда, которую вы проходите здесь, - это закрытие , особый тип метода, который волшебным образом перетаскивает из состояния метода, в котором он находится, и «закрывает» его.

... кроме того, что нет такой вещи, как магия. Все это состояние должно фактически жить где-то реальным, где-то связанным с методом закрытия и легко доступным из него. И что вы называете шаблоном программирования, где вы напрямую связываете состояние с одним или несколькими методами?

Правильно: классы. Компилятор преобразует лямбда в класс замыкания, а затем создает экземпляр класса внутри метода хостинга, поэтому метод хостинга может получить доступ к состоянию в классе.

Единственный способ избежать этого - не использовать закрытие. Если это действительно влияет на производительность, используйте цикл старой школы FOR вместо выражения LINQ.





any