CA1851: Możliwe wiele wyliczeń kolekcji IEnumerable
Właściwości | Wartość |
---|---|
Identyfikator reguły | CA1851 |
Tytuł | 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 9 | Nie. |
Przyczyna
Wykryto wiele wyliczeń IEnumerable
kolekcji.
Opis reguły
Kolekcja typu IEnumerable lub > 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.
Na 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.