Detected multiple enumerations of an IEnumerable collection.
Rule description
A collection of type IEnumerable or IEnumerable<T> has the ability to defer enumeration when it's generated. Many LINQ methods, such as Select, use deferred execution. Enumeration starts when the collection is passed into a LINQ enumeration method, like ElementAt, or used in a for each statement. The enumeration result is not calculated once and cached, like Lazy.
If the enumeration operation itself is expensive, for example, a query into a database, multiple enumerations would hurt the performance of the program.
If the enumeration operation has side effects, multiple enumerations might result in bugs.
How to fix violations
If the underlying type of your IEnumerable collection is some other type, such as List or Array, it's safe to convert the collection to its underlying type to fix the diagnostic.
Violation:
C#
publicvoidMyMethod(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
Fix:
C#
publicvoidMyMethod(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
If the underlying type of the IEnumerable collection uses an iterator-based implementation (for example, if it's generated by LINQ methods like Select or by using the yield keyword), you can fix the violation by materializing the collection. However, this allocates extra memory.
For example:
Violation:
C#
publicvoidMyMethod()
{
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
Fix:
C#
publicvoidMyMethod()
{
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
Configure customized enumeration methods and LINQ chain methods
By default, all the methods in the System.Linq namespace are included in the analysis scope. You can add custom methods that enumerate an IEnumerable argument into the scope by setting the enumeration_methods option in an .editorconfig file.
You can also add customized LINQ chain methods (that is, methods take an IEnumerable argument and return a new IEnumerable instance) to the analysis scope by setting the linq_chain_methods option in an .editorconfig file.
Configure the default assumption of methods take IEnumerable parameters
By default, all customized methods that accept an IEnumerable argument are assumed not to enumerate the argument. You can change this by setting the assume_method_enumerates_parameters option in an .editorconfig file.
When to suppress warnings
It's safe to suppress this warning if the underlying type of the IEnumerable collection is some other type like List or Array, or if you're sure that methods that take an IEnumerable collection don't enumerate it.
Suppress a warning
If you just want to suppress a single violation, add preprocessor directives to your source file to disable and then re-enable the rule.
C#
#pragmawarning disable CA1851// The code that's violating the rule is on this line.#pragmawarning restore CA1851
To disable the rule for a file, folder, or project, set its severity to none in the configuration file.
Izvor za ovaj sadržaj možete pronaći na GitHubu, gdje možete stvarati i pregledavati probleme i zahtjeve za povlačenjem. Dodatne informacije potražite u našem vodiču za suradnike.
Povratne informacije o proizvodu .NET
.NET je projekt otvorenog koda. Odaberite vezu za slanje povratnih informacija:
Pridružite se seriji susreta kako biste s kolegama programerima i stručnjacima izgradili skalabilna rješenja umjetne inteligencije temeljena na stvarnim slučajevima upotrebe.