2012-07-04 9 views
11

Ho un parametro IEnumerable che è necessario non vuoto. Se c'è una precondizione come quella qui sotto, la raccolta verrà enumerata durante questo. Ma verrà enumerato di nuovo la prossima volta che lo riferimento. (A "Possibile enumerazione multiplo di IEnumerable" avvertimento in ReSharper.)IEnumerazione di enumerazione multipla causata dalla precondizione del contratto

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

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

Queste soluzioni alternative fatte ReSharper felice, ma non sarebbe la compilazione:

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

Non ci sono altre soluzioni che sarebbero valide, ma forse no è sempre l'ideale come usare ICollection o IList, o eseguire una tipica eccezione if-null-throw.

Esiste una soluzione che funziona con i contratti di codice e IEnumerables come nell'esempio originale? Se no, allora qualcuno ha sviluppato un buon modello per aggirarlo?

+3

Penso che probabilmente è solo una cattiva idea quella di avere un contratto dipende da un IEnumerable - come IEnumerables per definizione può incorrere in effetti collaterali. –

+0

Finora ho usato ICollection come soluzione alternativa e non ho mai avuto problemi, anche se sono curioso di sapere se esiste una soluzione per IEnumerables. – Keith

risposta

7

utilizzare uno dei metodi progettati per funzionare con IEnumerable s, come Contract.Exists:

Determina se un elemento di un insieme di elementi esiste all'interno di una funzione.

Returns

vero se e solo se il predicato restituisce true per ogni elemento di tipo T in collezione.

Così il tuo predicato potrebbe semplicemente restituire true.


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

Anche questo non enumera l'elemento "IEnumerable"? – Rawling

+1

Solo se a) Avere attivato il controllo runtime e b) Non aver selezionato "Ignora quantificatori". (Anche se, in tal caso, ti consiglio di dividere in due "Richieste") –

+0

Ah OK. Quindi sarebbe corretto dire che né il codice originale né il codice _actually_ causano un'enumerazione (modulo a aeb sopra), ma ReSharper non lo realizza nel codice originale, e il tuo codice lo inserisce in una forma che RS ignora? – Rawling

Problemi correlati