2012-07-04 2 views
11

У меня есть параметр IEnumerable, который должен быть непустым. Если есть предварительное условие, подобное приведенному ниже, тогда коллекция будет перечисляться во время этого. Но в следующий раз я буду ссылаться на него. (А «Возможное кратное перечисление IEnumerable» предупреждение в Resharper.)IEnumerable множественное перечисление, вызванное предварительным условием контракта

void ProcessOrders(IEnumerable<int> orderIds) 
{ 
    Contract.Requires((orderIds != null) && orderIds.Any()); // enumerates the collection 

    // BAD: collection enumerated again 
    foreach (var i in orderIds) { /* ... */ } 
} 

Эти обходные сделали Resharper счастливым, но не компилируется:

// 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()); 

Есть другие обходные пути, которые были бы в силе, но, возможно, не всегда идеален, как использование ICollection или IList, или выполнение типичного исключения if-null-throw.

Есть ли решение, которое работает с кодовыми контрактами и IEnumerables, как в исходном примере? Если нет, то кто-то разработал хороший образец для работы вокруг него?

+3

Я думаю, что это, вероятно, просто плохая идея, чтобы иметь контракт, зависящий от IEnumerable - как IEnumerables по определению может понести побочные эффекты. –

+0

До сих пор я использовал ICollection как обходной путь и никогда не испытывал проблем, хотя мне любопытно, есть ли решение для IEnumerables. – Keith

ответ

7

Используйте один из методов, предназначенных для работы с IEnumerable с, таких как Contract.Exists:

Определяет, существует ли элемент в коллекции элементов внутри функции.

Возвращает

истинно тогда и только тогда, когда предикат возвращает истину для любого элемента типа T в коллекции.

Так что ваш предикат мог бы просто вернуть true.


Contract.Requires(orderIds != null); 
Contract.Requires(Contract.Exists(orderIds,a=>true)); 
+2

Будет ли это также не перечислять 'IEnumerable'? – Rawling

+1

Только если вы a) включили проверку времени выполнения и b) не выбрали «Skip Quantifiers». (Хотя в таком случае я бы рекомендовал разделить на два 'Requires') –

+0

Ah OK. Так что было бы правильно сказать, что ни исходный код, ни ваш код _actually_ не вызывают перечисление (по модулю ваши a и b выше), но ReSharper не понимает этого в исходном коде, и ваш код просто помещает его в форму, RS игнорирует? – Rawling

Смежные вопросы