Udostępnij przez


CA1851: Możliwe wiele wyliczeń kolekcji IEnumerable

Właściwości Wartość
Identyfikator reguły CA1851
Stanowisko Możliwe wiele wyliczeń kolekcji IEnumerable
Kategoria Wydajność
Poprawka powodująca niezgodność lub niezgodność Niezgodność
Wprowadzona wersja .NET 7
Domyślnie włączone na platformie .NET 8 Nie.

Przyczyna

Wykryto wiele wyliczeń IEnumerable kolekcji.

Opis reguły

Kolekcja typu IEnumerable lub IEnumerable<T> ma możliwość odroczenia wyliczenia podczas jego generowania. Wiele metod LINQ, takich jak Select, używa odroczonego wykonywania. Wyliczenie rozpoczyna się po przekazaniu kolekcji do metody wyliczenia LINQ, takiej jak ElementAt, lub używanej w instrukcji dla każdej instrukcji. Wynik wyliczenia nie jest obliczany raz i buforowany, na przykład Lazy.

Jeśli sama operacja wyliczenia jest kosztowna, na przykład zapytanie w bazie danych, wiele wyliczeń zaszkodziłoby wydajności programu.

Jeśli operacja wyliczania ma skutki uboczne, wiele wyliczeń może spowodować błędy.

Jak naprawić naruszenia

Jeśli podstawowym typem IEnumerable kolekcji jest inny typ, taki jak List lub Array, można bezpiecznie przekonwertować kolekcję na jej typ bazowy, aby naprawić diagnostykę.

Naruszenie:

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

Poprawka:

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

Jeśli podstawowy typ IEnumerable kolekcji używa implementacji opartej na iteratorze (na przykład jeśli jest generowany przez metody LINQ, takie jak Select lub przy użyciu słowa kluczowego yield ), można naprawić naruszenie, materializując kolekcję. Jednak spowoduje to przydzielenie dodatkowej pamięci.

Przykład:

Naruszenie:

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

Poprawka:

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

Konfigurowanie dostosowanych metod wyliczania i metod łańcucha LINQ

Domyślnie wszystkie metody w System.Linq przestrzeni nazw są uwzględniane w zakresie analizy. Możesz dodać metody niestandardowe, które wyliczają IEnumerable argument do zakresu, ustawiając enumeration_methods opcję w pliku .editorconfig .

Można również dodać niestandardowe metody łańcucha LINQ (czyli metody przyjmują IEnumerable argument i zwracają nowe IEnumerable wystąpienie) do zakresu analizy, ustawiając linq_chain_methods opcję w pliku editorconfig .

Konfigurowanie domyślnego założenia metod przyjmuje IEnumerable parametry

Domyślnie przyjmuje się, że wszystkie niestandardowe metody, które akceptują IEnumerable argument, nie są wyliczane argumentu. Możesz to zmienić, ustawiając assume_method_enumerates_parameters opcję w pliku .editorconfig .

Kiedy pomijać ostrzeżenia

Można bezpiecznie pominąć to ostrzeżenie, jeśli podstawowy typ IEnumerable kolekcji jest innym typem, takim jak List lub Array, lub jeśli masz pewność, że metody, które przyjmują IEnumerable kolekcję, nie wyliczają.

Pomijanie ostrzeżenia

Jeśli chcesz po prostu pominąć pojedyncze naruszenie, dodaj dyrektywy preprocesora do pliku źródłowego, aby wyłączyć, a następnie ponownie włączyć regułę.

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

Aby wyłączyć regułę dla pliku, folderu lub projektu, ustaw jego ważność na none w pliku konfiguracji.

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

Aby uzyskać więcej informacji, zobacz Jak pominąć ostrzeżenia dotyczące analizy kodu.

Zobacz też