2012-07-04 10 views
11

Tengo un parámetro IEnumerable que se requiere que no esté vacío. Si hay una precondición como la siguiente, la colección se enumerará durante el mismo. Pero se enumerará nuevamente la próxima vez que lo haga referencia. (Una "posible enumeración múltiplo de IEnumerable" de advertencia en ReSharper.)Enumerable enumeración múltiple causada por la condición previa del contrato

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

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

Estas soluciones hechas ReSharper feliz, pero no se compilará:

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

Hay otras soluciones que serían válidas, pero tal vez no siempre es ideal como usar ICollection o IList, o realizar una típica excepción de tiro nulo.

¿Existe alguna solución que funcione con contratos de código e IEnumerables como en el ejemplo original? Si no, ¿alguien ha desarrollado un buen patrón para solucionarlo?

+3

Creo que es probable que sólo una mala idea tener un contrato depende de un IEnumerable - como IEnumerables, por definición, puede incurrir en efectos secundarios. –

+0

Hasta ahora he usado ICollection como una solución alternativa y nunca tuve un problema, aunque tengo curiosidad por si hay una solución para IEnumerables. – Keith

Respuesta

7

uso uno de los métodos diseñados para trabajar con IEnumerable s, tales como Contract.Exists:

determina si existe un elemento dentro de una colección de elementos dentro de una función.

devoluciones

verdadero si y sólo si el predicado devuelve verdadero para cualquier elemento de tipo T en la colección.

Así que su predicado podría simplemente devolver true.


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

¿Esto no también enumerará el 'IEnumerable'? – Rawling

+1

Solo si a) Ha habilitado la comprobación de Runtime, y b) No ha seleccionado "Omitir cuantificadores". (Aunque, en tal caso, recomiendo dividirlo en dos 'Requires') –

+0

Ah OK. Entonces, sería correcto decir que ni el código original ni su código _realmente_ causan una enumeración (modifique su a y b arriba), pero ReSharper no se da cuenta de esto en el código original, y su código simplemente lo pone en una forma que RS ignora? – Rawling

Cuestiones relacionadas