CA1851: Possíveis enumerações múltiplas de IEnumerable
coleção
Propriedade | valor |
---|---|
ID da regra | CA1851 |
Cargo | Possíveis enumerações múltiplas de IEnumerable coleção |
Categoria | Desempenho |
A correção está quebrando ou não quebrando | Sem quebra |
Versão introduzida | .NET 7 |
Habilitado por padrão no .NET 8 | Não |
Causa
Detetadas várias enumerações de uma IEnumerable
coleção.
Descrição da regra
Uma coleção do tipo IEnumerable ou IEnumerable< T> tem a capacidade de adiar a enumeração quando ela é gerada. Muitos métodos LINQ, como Select, usam execução adiada. A enumeração começa quando a coleção é passada para um método de enumeração LINQ, como ElementAt, ou usada em um para cada instrução. O resultado da enumeração não é calculado uma vez e armazenado em cache, como Lazy.
Se a operação de enumeração em si for cara, por exemplo, uma consulta em um banco de dados, várias enumerações prejudicariam o desempenho do programa.
Se a operação de enumeração tiver efeitos colaterais, várias enumerações podem resultar em bugs.
Como corrigir violações
Se o tipo subjacente da sua IEnumerable
coleção for algum outro tipo, como List
ou Array
, é seguro converter a coleção para o tipo subjacente para corrigir o diagnóstico.
Violação:
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
Correção:
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 o tipo subjacente da IEnumerable
coleção usar uma implementação baseada em iterador (por exemplo, se for gerada por métodos LINQ como Select ou usando a palavra-chave yield), você poderá corrigir a violação materializando a coleção. No entanto, isso aloca memória extra.
Por exemplo:
Violação:
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
Correção:
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
Configurar métodos de enumeração personalizados e métodos de cadeia LINQ
Por padrão, todos os métodos no namespace são incluídos no System.Linq escopo da análise. Você pode adicionar métodos personalizados que enumeram um argumento no escopo definindo a opção em um IEnumerable
arquivo .editorconfig.enumeration_methods
Você também pode adicionar métodos de cadeia LINQ personalizados (ou seja, os métodos usam um argumento e retornam uma nova IEnumerable
instância) ao escopo da análise definindo a linq_chain_methods
opção em um IEnumerable
arquivo .editorconfig.
Configurar a suposição padrão de métodos tomar IEnumerable
parâmetros
Por padrão, todos os métodos personalizados que aceitam um IEnumerable
argumento são assumidos para não enumerar o argumento. Você pode alterar isso definindo a assume_method_enumerates_parameters
opção em um arquivo .editorconfig .
Quando suprimir avisos
É seguro suprimir esse aviso se o tipo subjacente da coleção for algum outro tipo como List
ou , ou Array
se você tiver certeza de que os IEnumerable
métodos que usam uma IEnumerable
coleção não a enumeram.
Suprimir um aviso
Se você quiser apenas suprimir uma única violação, adicione diretivas de pré-processador ao seu arquivo de origem para desativar e, em seguida, reativar a regra.
#pragma warning disable CA1851
// The code that's violating the rule is on this line.
#pragma warning restore CA1851
Para desabilitar a regra para um arquivo, pasta ou projeto, defina sua severidade como none
no arquivo de configuração.
[*.{cs,vb}]
dotnet_diagnostic.CA1851.severity = none
Para obter mais informações, consulte Como suprimir avisos de análise de código.