CA1851: Posibles enumeraciones múltiples de la colección IEnumerable
Propiedad | Value |
---|---|
Identificador de la regla | CA1851 |
Título | Posibles enumeraciones múltiples de IEnumerable colección |
Categoría | Rendimiento |
La corrección es problemática o no problemática | Poco problemático |
Versión introducida | .NET 7 |
Habilitado de forma predeterminada en .NET 9 | No |
Causa
Se detectaron varias enumeraciones de una colección IEnumerable
.
Descripción de la regla
Una colección de tipo IEnumerable o IEnumerable<T> tiene la capacidad de aplazar la enumeración cuando se genera. Muchos métodos LINQ, como Select, usan la ejecución diferida. La enumeración se inicia cuando la colección se pasa a un método de enumeración LINQ, como ElementAt, o cuando se usa en una instrucción for each. El resultado de la enumeración no se calcula una vez y se almacena en caché, como Lazy.
Si la propia operación de enumeración es costosa, por ejemplo, una consulta en una base de datos, varias enumeraciones perjudicarían el rendimiento del programa.
Si la operación de enumeración tiene efectos secundarios, es posible que varias enumeraciones produzcan errores.
Cómo corregir infracciones
Si el tipo subyacente de la colección IEnumerable
es otro tipo, como List
o Array
, es seguro convertir la colección en su tipo subyacente para corregir el diagnóstico.
Infracción:
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
Corrección:
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
Si el tipo subyacente de la colección IEnumerable
usa una implementación basada en iteradores (por ejemplo, si se genera mediante métodos LINQ como Select o mediante la palabra clave yield), puede corregir la infracción materializando la colección. No obstante, esto asigna memoria adicional.
Por ejemplo:
Infracción:
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
Corrección:
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
Configuración de métodos de enumeración personalizados y métodos de cadena LINQ
De forma predeterminada, todos los métodos del espacio de nombres System.Linq se incluyen en el ámbito de análisis. Puede agregar métodos personalizados que enumeren un argumento IEnumerable
en el ámbito estableciendo la opción enumeration_methods
en un archivo .editorconfig.
También puede agregar métodos de cadena LINQ personalizados (es decir, los métodos toman un argumento IEnumerable
y devuelven una nueva instancia IEnumerable
) al ámbito de análisis estableciendo la opción linq_chain_methods
en un archivo .editorconfig.
La configuración de la suposición predeterminada de métodos toma parámetros IEnumerable
De forma predeterminada, se supone que todos los métodos personalizados que aceptan un argumento IEnumerable
no enumeran el argumento. Puede cambiarlo estableciendo la opción assume_method_enumerates_parameters
en un archivo .editorconfig.
Cuándo suprimir las advertencias
Es seguro suprimir esta advertencia si el tipo subyacente de la colección IEnumerable
es de otro tipo como List
o Array
, o si está seguro de que los métodos que toman una colección IEnumerable
no lo enumeran.
Supresión de una advertencia
Si solo quiere suprimir una única infracción, agregue directivas de preprocesador al archivo de origen para deshabilitar y volver a habilitar la regla.
#pragma warning disable CA1851
// The code that's violating the rule is on this line.
#pragma warning restore CA1851
Para deshabilitar la regla de un archivo, una carpeta o un proyecto, establezca su gravedad en none
del archivo de configuración.
[*.{cs,vb}]
dotnet_diagnostic.CA1851.severity = none
Para obtener más información, consulte Procedimiento para suprimir advertencias de análisis de código.