CA1851: Possíveis enumerações múltiplas de IEnumerable
coleção
Property | valor |
---|---|
ID da regra | CA1851 |
Título | 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 9 | Não |
Motivo
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 System.Linq namespace são incluídos no escopo da análise. Você pode adicionar métodos personalizados que enumeram um IEnumerable
argumento no escopo definindo a enumeration_methods
opção em um arquivo .editorconfig .
Você também pode adicionar métodos de cadeia LINQ personalizados (ou seja, os métodos usam um IEnumerable
argumento e retornam uma nova IEnumerable
instância) ao escopo da análise definindo a linq_chain_methods
opção em um 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 Array
, ou 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 de um arquivo, pasta ou projeto, defina sua gravidade 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.