CA1851: Mögliche mehrere Enumerationen der „IEnumerable
“-Auflistung
Eigenschaft | Wert |
---|---|
Regel-ID | CA1851 |
Titel | Mögliche mehrere Enumerationen der IEnumerable -Auflistung |
Kategorie | Leistung |
Fix führt oder führt nicht zur Unterbrechung | Nicht unterbrechend |
Eingeführt in Version | .NET 7 |
Standardmäßig in .NET 8 aktiviert | Nein |
Ursache
Es wurden mehrere Enumerationen einer IEnumerable
-Auflistung erkannt.
Regelbeschreibung
Eine Auflistung vom Typ IEnumerable oder IEnumerable<T> hat die Möglichkeit, die Enumeration zurückzustellen, wenn sie generiert wird. Viele LINQ-Methoden wie beispielsweise Select verwenden die verzögerte Ausführung. Die Enumeration beginnt, wenn die Auflistung an eine LINQ-Enumerationsmethode wie ElementAt übergeben oder in einer for each-Anweisung verwendet wird. Das Enumerationsergebnis wird nicht einmal berechnet und zwischengespeichert, wie z. B. Lazy.
Wenn der Enumerationsvorgang selbst aufwendig ist, z. B. eine Abfrage in einer Datenbank, würden mehrere Enumerationen die Leistung des Programms beeinträchtigen.
Wenn der Enumerationsvorgang Nebenwirkungen hat, können mehrere Enumerationen zu Fehlern führen.
Behandeln von Verstößen
Wenn der zugrunde liegende Typ Ihrer IEnumerable
-Auflistung ein anderer Typ ist, z. B. List
oder Array
, ist es sicher, die Auflistung in den zugrunde liegenden Typ zu konvertieren, um die Diagnose zu korrigieren.
Verstoß:
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
Korrektur:
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
Wenn der zugrunde liegende Typ der IEnumerable
-Auflistung eine iteratorbasierte Implementierung verwendet (z. B. wenn sie von LINQ-Methoden wie Select oder mithilfe der Schlüsselworts yield generiert wird), können Sie den Verstoß beheben, indem Sie die Auflistung materialisieren. Dadurch wird jedoch zusätzlicher Arbeitsspeicher zugewiesen.
Beispiel:
Verstoß:
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
Korrektur:
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
Konfigurieren von angepassten Enumerationsmethoden und LINQ-Kettenmethoden
Standardmäßig sind alle Methoden im Namespace System.Linq im Analyseumfang enthalten. Sie können benutzerdefinierte Methoden hinzufügen, die ein IEnumerable
-Argument in den Umfang enumerieren, indem Sie die Option enumeration_methods
in einer .editorconfig-Datei festlegen.
Sie können auch angepasste LINQ-Kettenmethoden (d. h. Methoden, die ein IEnumerable
-Argument akzeptieren und eine neue IEnumerable
-Instanz zurückgeben) zum Analysebereich hinzufügen, indem Sie die Option linq_chain_methods
in einer .editorconfig--Datei festlegen.
Konfigurieren der Standardannahme, dass Methoden IEnumerable
-Parameter akzeptieren
Standardmäßig wird bei allen angepassten Methoden, die ein IEnumerable
-Argument akzeptieren, angenommen, dass sie das Argument nicht enumerieren. Diese Einstellung können Sie ändern, indem Sie die Option assume_method_enumerates_parameters
in einer .editorconfig--Datei festlegen.
Wann sollten Warnungen unterdrückt werden?
Es ist sicher, diese Warnung zu unterdrücken, wenn der zugrunde liegende Typ der IEnumerable
-Auflistung ein anderer Typ wie z. B. List
oder Array
ist oder wenn Sie sicher sind, dass Methoden, die eine IEnumerable
-Auflistung akzeptieren, diese nicht enumerieren.
Unterdrücken einer Warnung
Um nur eine einzelne Verletzung zu unterdrücken, fügen Sie der Quelldatei Präprozessoranweisungen hinzu, um die Regel zu deaktivieren und dann wieder zu aktivieren.
#pragma warning disable CA1851
// The code that's violating the rule is on this line.
#pragma warning restore CA1851
Um die Regel für eine Datei, einen Ordner oder ein Projekt zu deaktivieren, legen Sie den Schweregrad in der Konfigurationsdatei auf none
fest.
[*.{cs,vb}]
dotnet_diagnostic.CA1851.severity = none
Weitere Informationen finden Sie unter Vorgehensweise: Unterdrücken von Codeanalyse-Warnungen.