Sdílet prostřednictvím


CA1851: Možné více výčtů IEnumerable kolekce

Vlastnost Hodnota
ID pravidla CA1851
Název Možné více výčtů IEnumerable kolekce
Kategorie Výkon
Oprava způsobující chybu nebo chybu způsobující chybu Nenarušující
Zavedená verze .NET 7
Povoleno ve výchozím nastavení v .NET 9 No

Příčina

Zjistilo se více výčtů IEnumerable kolekce.

Popis pravidla

Kolekce typu IEnumerable nebo IEnumerable<T> má schopnost odložit výčet při generování. Mnoho metod LINQ, například Select, používá odložené spuštění. Výčet se spustí, když se kolekce předá do metody výčtu LINQ, jako je ElementAt, nebo použit v příkazu pro každý příkaz. Výsledek výčtu se nevypočítá jednou a ukládá se do mezipaměti, jako je Lazy.

Pokud je samotná operace výčtu nákladná, například dotaz do databáze, více výčtů by poškodilo výkon programu.

Pokud má operace výčtu vedlejší účinky, může mít několik výčtů za následek chyby.

Jak opravit porušení

Pokud je podkladovým typem kolekce IEnumerable jiný typ, například List nebo Array, je bezpečné převést kolekci na základní typ a opravit tak diagnostiku.

Porušení:

public void MyMethod(IEnumerable<int> input)
{
    var count = input.Count();
    foreach (var i in input) { }
}
Public Sub MyMethod(input As IEnumerable(Of Integer))
    Dim count = input.Count()
    For Each i In input
    Next
End Sub

Oprava:

public void MyMethod(IEnumerable<int> input)
{
    // If the underlying type of 'input' is List<int>
    var inputList = (List<int>)input;
    var count = inputList.Count();
    foreach (var i in inputList) { }
}
Public Sub MyMethod(input As IEnumerable(Of Integer))
    ' If the underlying type of 'input' is array
    Dim inputArray = CType(input, Integer())
    Dim count = inputArray.Count()
    For Each i In inputArray
    Next
End Sub

Pokud základní typ IEnumerable kolekce používá implementaci založenou na iterátoru (například pokud je vygenerována metodami LINQ, jako Select je nebo pomocí klíčového slova výnos ), můžete opravit porušení tím, že kolekci materializujete. Tím se ale přiděluje další paměť.

Příklad:

Porušení:

public void MyMethod()
{
    var someStrings = GetStrings().Select(i => string.Concat("Hello"));

    // It takes 2 * O(n) to complete 'Count()' and 'Last()' calls, where 'n' is the length of 'someStrings'.
    var count = someStrings.Count();
    var lastElement = someStrings.Last();
}
Public Sub MyMethod()
    Dim someStrings = GetStrings().Select(Function(i) String.Concat(i, "Hello"))

    ' It takes 2 * O(n) to complete 'Count()' and 'Last()' calls, where 'n' is the length of 'someStrings'.
    Dim count = someStrings.Count()
    Dim lastElement = someStrings.Last()
End Sub

Oprava:

public void MyMethod()
{
    var someStrings = GetStrings().Select(i => string.Concat("Hello"));
    // Materialize it into an array.
    // Note: This operation would allocate O(n) memory,
    // and it takes O(n) time to finish, where 'n' is the length of 'someStrings'.
    var someStringsArray = someStrings.ToArray()

    // It takes 2 * O(1) to complete 'Count()' and 'Last()' calls.
    var count = someStringsArray.Count();
    var lastElement = someStringsArray.Last();
}
Public Sub MyMethod()
    Dim someStrings = GetStrings().Select(Function(i) String.Concat(i, "Hello"))
    ' Materialize it into an array.
    ' Note: This operation would allocate O(n) memory,
    ' and it takes O(n) time to finish, where 'n' is the length of 'someStrings'.
    Dim someStringsArray = someStrings.ToArray()

    ' It takes 2 * O(1) to complete 'Count()' and 'Last()' calls.
    Dim count = someStrings.Count()
    Dim lastElement = someStrings.Last()
End Sub

Konfigurace přizpůsobených metod výčtu a metod řetězu LINQ

Ve výchozím nastavení jsou všechny metody v System.Linq oboru názvů zahrnuty do oboru analýzy. Můžete přidat vlastní metody, které vyčíslí IEnumerable argument do oboru nastavením enumeration_methods možnosti v souboru .editorconfig .

Do oboru analýzy můžete také přidat přizpůsobené metody řetězu LINQ (tj. metody přebírají IEnumerable argument a vrátit novou IEnumerable instanci) nastavením linq_chain_methods možnosti v souboru .editorconfig .

Konfigurace výchozího předpokladu metod přebírá IEnumerable parametry

Ve výchozím nastavení se předpokládá, že všechny přizpůsobené metody, které přijímají IEnumerable argument, nejsou výčet argumentu. Můžete to změnit nastavením assume_method_enumerates_parameters možnosti v souboru .editorconfig .

Kdy potlačit upozornění

Toto upozornění je bezpečné potlačit, pokud je podkladovým typem IEnumerable kolekce jiný typ, Arraynapříklad List nebo nebo pokud jste si jisti, že metody, které kolekci nevyčtouIEnumerable, ji nevyčtou.

Potlačení upozornění

Pokud chcete pouze potlačit jedno porušení, přidejte do zdrojového souboru direktivy preprocesoru, abyste pravidlo zakázali a znovu povolili.

#pragma warning disable CA1851
// The code that's violating the rule is on this line.
#pragma warning restore CA1851

Pokud chcete pravidlo pro soubor, složku nebo projekt zakázat, nastavte jeho závažnost v none konfiguračním souboru.

[*.{cs,vb}]
dotnet_diagnostic.CA1851.severity = none

Další informace naleznete v tématu Jak potlačit upozornění analýzy kódu.

Viz také