CA1851: possibili enumerazioni di IEnumerable raccolta

Proprietà valore
ID regola CA1851
Titolo Possibili enumerazioni multiple di IEnumerable raccolta
Categoria Prestazioni
Correzione che causa un'interruzione o un'interruzione Nessuna interruzione
Versione introdotta .NET 7
Abilitato per impostazione predefinita in .NET 8 No

Causa

Rilevate più enumerazioni di una IEnumerable raccolta.

Descrizione regola

Una raccolta di tipo IEnumerable o IEnumerable< T> può rinviare l'enumerazione quando viene generata. Molti metodi LINQ, ad esempio Select, usano l'esecuzione posticipata. L'enumerazione viene avviata quando la raccolta viene passata in un metodo di enumerazione LINQ, ad esempio ElementAt o usata in un oggetto per ogni istruzione. Il risultato dell'enumerazione non viene calcolato una volta e memorizzato nella cache, ad esempio Lazy.

Se l'operazione di enumerazione stessa è costosa, ad esempio una query in un database, più enumerazioni potrebbero compromettere le prestazioni del programma.

Se l'operazione di enumerazione ha effetti collaterali, più enumerazioni potrebbero causare bug.

Come correggere le violazioni

Se il tipo sottostante della IEnumerable raccolta è un altro tipo, ad esempio List o Array, è possibile convertire la raccolta nel tipo sottostante per correggere la diagnostica.

Violazione:

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

Correzione:

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

Se il tipo sottostante della IEnumerable raccolta usa un'implementazione basata su iteratore, ad esempio se viene generata da metodi LINQ come Select o usando la parola chiave yield , è possibile correggere la violazione materializzando la raccolta. Tuttavia, alloca memoria aggiuntiva.

Ad esempio:

Violazione:

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

Correzione:

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

Configurare metodi di enumerazione personalizzati e metodi della catena LINQ

Per impostazione predefinita, tutti i metodi nello spazio dei System.Linq nomi sono inclusi nell'ambito di analisi. È possibile aggiungere metodi personalizzati che enumerare un IEnumerable argomento nell'ambito impostando l'opzione enumeration_methods in un file con estensione editorconfig .

È anche possibile aggiungere metodi della catena LINQ personalizzati( ovvero i metodi accettano un IEnumerable argomento e restituiscono una nuova IEnumerable istanza) all'ambito di analisi impostando l'opzione linq_chain_methods in un file con estensione editorconfig .

Configurare il presupposto predefinito dei metodi accetta IEnumerable parametri

Per impostazione predefinita, si presuppone che tutti i metodi personalizzati che accettano un IEnumerable argomento non enumerino l'argomento. È possibile modificare questa impostazione impostando l'opzione assume_method_enumerates_parameters in un file con estensione editorconfig .

Quando eliminare gli avvisi

È possibile eliminare questo avviso se il tipo sottostante della IEnumerable raccolta è un altro tipo, ad List esempio o Array, oppure se si è certi che i metodi che accettano una IEnumerable raccolta non lo enumerino.

Eliminare un avviso

Se si vuole eliminare una singola violazione, aggiungere direttive del preprocessore al file di origine per disabilitare e quindi riabilitare la regola.

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

Per disabilitare la regola per un file, una cartella o un progetto, impostarne la gravità none su nel file di configurazione.

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

Per altre informazioni, vedere Come eliminare gli avvisi di analisi del codice.

Vedi anche