2010-05-06 10 views
5

Ho un po 'di codice con la seguente logica:Cosa fare quando si utilizza Contract.Assert (true) e il metodo deve restituire qualcosa?

//pseudo-code 
foreach (element in elementList) { 
    if (element is whatever) 
     return element; 
    } 
} 

In teoria, c'è sempre un elemento che è qualsiasi cosa, quindi questo metodo non dovrebbe porre problemi. In ogni caso, ho messo un'affermazione sulla fine del metodo giusto per essere sicuri:

//pseudo-code 
foreach (element in elementList) { 
    if (element is whatever) 
     return element; 
    } 
} 

Contract.Assert(false, "Invalid state!"); 

Il problema è che, come questo metodo deve restituire qualcosa, e il compilatore non capire che l'affermazione interromperà l'esecuzione del programma. Prima di usare Contratti, in questo tipo di situazioni, usavo lanciare un'eccezione, che risolveva il problema. Come gestiresti questo con Contract.Assert()? Restituisce null o default (element_type) dopo la chiamata Contract.Assert() sapendo che non verrà mai chiamata e chiudendo il compilatore? O c'è qualche altro modo più elegante per farlo?

Grazie

+0

Non dire 'Contract.Assert (false, "stato non valido!");'? –

+0

Sì, l'ho fatto. : facep: –

risposta

2

si potrebbe andare con

var result = null; 
foreach (element in elementList) { 
    if (element is whatever) 
     result = element; 
     break; 
    } 
} 

Contract.Assert(result != null, "Invalid state!"); 
return result; 

introduce una pausa, ma ha un aspetto più pulito in tutto il ritorno.

ancora più pulito sarebbe

return elementList.Where(e => e is whatever).First(); 

Modifica come @devoured rilevare quanto sopra avrebbe colpito l'intera lista

più pulito senza il cui

return elementList.First(e => e is whatever); 

modificare fine

Questo esplode se non viene trovato nulla.

Ma se si vuole veramente l'asserzione che potrebbe essere

var results = elementList.Where(e => e is whatever); 
Contract.Assert(results.Count() == 1, "Boo"); 
return results.First(); 

ma che itererà l'intera lista troppo.

+0

Informazioni sull'uso di LINQ's First, eseguirà l'intera lista elementi, o smetterà di cercare altri elementi nel momento in cui trova il primo? –

+1

@devoured Penso che mentre scrivo verrà eseguita l'intera lista. Ma forse usarlo come 'elementList.First (e => e è qualunque cosa)' (nota la mancanza di 'Where') dovrebbe fermarsi al primo. Ma non l'ho testato –

+0

Oooooooops.Ho sbagliato il "Accetta il pulsante di risposta" e ho votato. Devi modificare la tua risposta in modo da permettermi di cambiare la votazione :( –

1

Penso che staresti meglio con uno Contract.Requires (vale a dire una precondizione) rispetto a uno Contract.Assert qui. La precondizione per il tuo frammento di codice è che elementList contiene almeno un elemento in cui la condizione è valida.

si dovrebbe essere esplicito su che, piuttosto che fare affidamento su un Assert(false), che richiede al lettore di capire il resto della funzione e seguire il controllo del flusso di dedurre le situazioni in cui viene raggiunto il Assert(false).

Quindi, mi piacerebbe riscrivere come:

//precondition (checked only in debug builds) 
Contract.Require(elementList.Where(e => e is whatever).Count > 0,"elementList requires at least one element meeting condition whatever"); 
//do work (throws in release builds, never reached in debug ones) 
return elementList.First(e => e is whatever); 
+0

-, quindi dovrai ripetere l'elenco due volte ... e quella non è la ciliegina sulla parte superiore ... stai anche usando '.Count()> 0' (la chiamata di proprietà non è possibile poiché il ritorno di' .Where() 'è' IEnumerable ', e quel tipo non ha la proprietà' .Count', ma piuttosto un metodo di estensione ... 'Enumerable.Count()') che ha bisogno di scorrere l'intero risultato - piuttosto usa '.Any()' –

+0

No. Qualcuno non capisce come funzionano i contratti, ogni volta che la velocità è importante la mia risposta scorre sull'elenco al massimo una volta. La precondizione rende il codice più leggibile, supporta il debug e funge da suggerimento per l'ottimizzatore. Non viene eseguito nel codice di produzione. –

+0

No. Qualcuno non capisce come funziona Linq (per favore leggi http://stackoverflow.com/questions/305092/which-method-performs-better-any-vs-count-0), e che la proprietà 'Count' non esiste su un 'IEnumerable ' - tuttavia, l'esecuzione di 'Contract.Require' è una questione di configurazione (nota anche come' Esegui controllo contratto runtime': ** 'Completo' **,' Pre e post', ...). –

Problemi correlati