I have an IEnumerable
parameter that is required to be non-empty. If there's a precondition like the one below then the collection will be enumerated during it. But it will be enumerated again the next time I reference it, thereby causing a "Possible multiple enumeration of IEnumerable" warning in Resharper.
void ProcessOrders(IEnumerable<int> orderIds)
{
Contract.Requires((orderIds != null) && orderIds.Any()); // enumerates the collection
// BAD: collection enumerated again
foreach (var i in orderIds) { /* ... */ }
}
These workarounds made Resharper happy but wouldn't compile:
// enumerating before the precondition causes error "Malformed contract. Found Requires
orderIds = orderIds.ToList();
Contract.Requires((orderIds != null) && orderIds.Any());
---
// enumerating during the precondition causes the same error
Contract.Requires((orderIds != null) && (orderIds = orderIds.ToList()).Any());
There are other workarounds that would be valid but maybe not always ideal like using ICollection or IList, or performing a typical if-null-throw-exception.
Is there a solution that works with code contracts and IEnumerables like in the original example? If not then has someone developed a good pattern for working around it?
The problem with taking IEnumerable as a parameter is that it tells callers "I wish to enumerate this". It doesn't tell them how many times you wish to enumerate. I can change the objects parameter to be List and then avoid the possible multiple enumeration but then I don't get the highest object that I can handle.
The issue is that the consumer of the enumerable isn't necessarily the owner of it, and so doesn't know if it's safe to enumerate multiple times. If it is safe, or if the method has a requirement to be able to enumerate multiple times, it might be more appropriate to accept an IList or IReadOnlyList as the parameter to the API.
Making ever user of an IEnumerable convert it to a list seems like a bad idea. The issue is that the consumer of the enumerable isn't necessarily the owner of it, and so doesn't know if it's safe to enumerate multiple times.
It just means the IEnumerable is evaluated twice, wich is usually not a problem unless the evaluation itself takes a long time. Even if it does take a long time, in this case your only using one element the first time around. In this scenario you could also exploit the powerful linq extension methods even more.
Use one of the methods designed to work with IEnumerable
s, such as Contract.Exists
:
Determines whether an element within a collection of elements exists within a function.
Returns
true if and only if predicate returns true for any element of type T in collection.
So your predicate could just return true
.
Contract.Requires(orderIds != null);
Contract.Requires(Contract.Exists(orderIds,a=>true));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With