CA1851: возможные несколько перечислений IEnumerable
коллекции
Свойство | Значение |
---|---|
Идентификатор правила | CA1851 |
Заголовок | Возможные несколько перечислений IEnumerable коллекции |
Категория | Производительность |
Исправление является критическим или не критическим | Не критическое |
Представленные версии | .NET 7 |
Включен по умолчанию в .NET 9 | No |
Причина
Обнаружено несколько перечислений IEnumerable
коллекции.
Описание правила
Коллекция типов IEnumerable или IEnumerable< T> имеет возможность отложить перечисление при его создании. Многие методы LINQ, такие как Select, используют отложенное выполнение. Перечисление начинается, когда коллекция передается в метод перечисления LINQ, например ElementAt, или используется в каждой инструкции. Результат перечисления не вычисляется один раз и кэшируется, например Lazy.
Если операция перечисления является дорогой, например запрос в базу данных, несколько перечислений повреждют производительность программы.
Если операция перечисления имеет побочные эффекты, несколько перечислений могут привести к ошибкам.
Устранение нарушений
Если базовый тип IEnumerable
коллекции является другим типом, например List
или Array
, можно преобразовать коллекцию в его базовый тип, чтобы исправить диагностику.
Нарушение:
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
Исправление:
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
Если базовый тип IEnumerable
коллекции использует реализацию на основе итератора (например, если она создается методами LINQ, например Select или с помощью ключевого слова получения ), можно устранить нарушение, материализуя коллекцию. Однако это выделяет дополнительную память.
Например:
Нарушение:
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
Исправление:
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
Настройка настраиваемых методов перечисления и методов LINQ chain
По умолчанию все методы в пространстве имен включены в System.Linq область анализа. Можно добавить настраиваемые методы, перечисляющие IEnumerable
аргумент в область, задав enumeration_methods
параметр в файле editorconfig .
Можно также добавить настраиваемые методы LINQ chain (т. е. методы принимают IEnumerable
аргумент и возвращают новый IEnumerable
экземпляр) в область анализа, задав linq_chain_methods
параметр в файле editorconfig .
Настройка допущения по умолчанию методов принимает IEnumerable
параметры
По умолчанию предполагается, что все настраиваемые методы, принимаюющие IEnumerable
аргумент, не перечисляют аргумент. Это можно изменить, задав assume_method_enumerates_parameters
параметр в файле editorconfig .
Когда лучше отключить предупреждения
Это предупреждение безопасно подавлять, если базовый тип IEnumerable
коллекции является другим типом, например List
или Array
, если вы уверены, что методы, которые IEnumerable
принимают коллекцию, не перечисляют его.
Отключение предупреждений
Если вы просто хотите отключить одно нарушение, добавьте директивы препроцессора в исходный файл, чтобы отключить и повторно включить правило.
#pragma warning disable CA1851
// The code that's violating the rule is on this line.
#pragma warning restore CA1851
Чтобы отключить правило для файла, папки или проекта, задайте его серьезность none
в файле конфигурации.
[*.{cs,vb}]
dotnet_diagnostic.CA1851.severity = none
Дополнительные сведения см. в разделе Практическое руководство. Скрытие предупреждений анализа кода.