12
votes

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?

1
I think it's probably just a bad idea to have a contract dependant on an IEnumerable - as IEnumerables by definition can incur side effects.Dave Bish
So far I've used ICollection as a workaround and never had a problem, though I'm curious if there's a solution for IEnumerables.Keith

1 Answers

8
votes

Use one of the methods designed to work with IEnumerables, 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));