2010-12-15 11 views
17

Fuori della parte superiore della mia testa, posso pensare di 4 modi per verificare la presenza di argomenti nulli:Pro/contro di diversi metodi per testare le condizioni preliminari?

Debug.Assert(context != null); 
Contract.Assert(context != null); 
Contract.Requires(context != null); 
if (context == null) throw new ArgumentNullException("context"); 

ho sempre usato l'ultimo metodo, ma ho appena visto un frammento di codice che ha utilizzato Contract.Requires, che ho non mi sono familiare Quali sono i vantaggi/svantaggi di ciascun metodo? Ci sono altri modi?


In VS2010 w/ReSharper,

  • Contract.Assert mi avverte che l'espressione è sempre vero (come sa, io non sono molto sicuro ... non può essere nullo HttpContext?),
  • Contract.Requires ottiene sbiadito fuori e mi dice il compilatore non richiamare il metodo (presumo a causa del primo motivo, non potrà mai essere nullo), e
  • se cambio l'ultimo metodo per context != null tutto il codice follo la vela si dissolve e mi dice che il codice è euristicamente irraggiungibile.

Quindi, sembra che gli ultimi 3 metodi abbiano una sorta di intelligenza integrata nel controllore statico VS, e Debug.Assert è semplicemente stupido.

+0

La domanda non è chiara. Stai davvero provando a usarli tutti in una volta? –

+0

@Matthew: Non sono sicuro di come non sia chiaro ... no, non sto cercando di usarli tutti in una volta. Ho creato uno snippet di codice del genere solo per illustrare i diversi modi in cui è possibile verificare la nullità. – mpen

+0

Questo è quello che ho pensato dal resto della domanda, ma la presentazione della sintassi che hai usato era strana. –

risposta

12

Suppongo che sia stato applicato un contratto all'interfaccia IHttpHandler.ProcessRequest che richiede quel contesto! = Null. I contratti di interfaccia sono ereditati dai loro implementatori, quindi non è necessario ripetere le Richieste. In effetti, non è consentito aggiungere ulteriori dichiarazioni di Requisiti, in quanto si è limitati ai requisiti associati al contratto di interfaccia.

Penso che sia importante distinguere tra specificare un obbligo contrattuale e semplicemente eseguire un controllo nullo. È possibile implementare un controllo Null e generare un'eccezione in fase di runtime, in modo da informare lo sviluppatore che stanno utilizzando correttamente l'API. Un'espressione Contract, d'altra parte, è in realtà una forma di metadati, che può essere interpretata dal rewriter del contratto (per introdurre le eccezioni del runtime precedentemente implementate manualmente), ma anche dall'analizzatore statico, che può utilizzarle per ragionare sulla correttezza statica della tua applicazione.

Detto questo, se si sta lavorando in un ambiente in cui si stanno attivamente utilizzando i Contratti di codice e l'analisi statica, è decisamente preferibile inserire le asserzioni nel modulo Contratto per sfruttare l'analisi statica. Anche se non stai usando l'analisi statica, puoi comunque lasciare la porta aperta per benefici successivi usando i contratti. La cosa principale a cui prestare attenzione è se i progetti sono stati configurati per eseguire la riscrittura, altrimenti i contratti non genereranno eccezioni di runtime come ci si potrebbe aspettare.


di approfondire ciò che i commentatori hanno detto, la differenza tra Assert, assumere e richiede è:

  • Un Contract.Assert espressione si trasforma in un'affermazione del rewriter contratto e l'analizzatore statico tenta di dimostrare l'espressione sulla base delle prove esistenti. Se non può essere provato, riceverai un avviso di analisi statica.
  • Un'espressione Contract.Assume viene ignorata dal redattore del contratto (per quanto ne so), ma viene interpretata dall'analizzatore statico come una nuova prova che può prendere in considerazione nella sua analisi statica. Contrarre.Assume è usato per "colmare le lacune" nell'analisi statica, o dove manca la sofisticazione per fare le inferenze necessarie o quando interagisce con il codice che non è stato decorato con i Contratti, in modo da poter assumere, ad esempio, che una particolare chiamata di funzione restituisce un risultato non nullo.
  • Contract.Requires sono condizioni che devono sempre essere true quando viene chiamato il metodo. Possono essere vincoli sui parametri del metodo (che sono i più tipici) e possono anche essere vincoli sugli stati dell'oggetto visibili pubblicamente (ad esempio, è possibile consentire il richiamo del metodo solo se Initialized è True.) Questi tipi dei vincoli spingono gli utenti della classe a verificare Initialized quando usano l'oggetto (e presumibilmente gestiscono l'errore appropriatamente se non lo sono) o creano i propri vincoli e/o invarianti di classe per chiarire che l'inizializzazione è avvenuta.
+0

Quindi ... qual è esattamente la differenza tra "Contract.Assert" e "Contract.Requires"? – mpen

+2

@ Ralph: 'Contract.Requires' indica le cose che dovrebbero essere vere quando viene chiamato il metodo,' Contract.Assert' dovrebbe andare nel mezzo del metodo per controllare gli stati intermedi. Aggiungere 'Contract.Assert's nel posto giusto può aiutare l'analizzatore statico a provare il codice corretto se non riesce a gestirlo da solo. –

+3

In realtà, il controllo statico trarrebbe beneficio solo dal contratto.Assume. Questo metodo si comporta come Contract.Assert in fase di esecuzione, ma indica al controllore statico di non provare e lo dimostra statisticamente. – koenmetsu

2

Il primo metodo è appropriato per il test di una condizione nulla che non dovrebbe mai esistere. Cioè, usalo durante lo sviluppo per assicurarti che non venga imprevedibilmente azzerato. Poiché non gestisce alcun errore, questo non è appropriato per la gestione di condizioni nulle nel prodotto rilasciato.

Direi che la 2a e 3a versione sono simili in quanto non gestiscono il problema in alcun modo.

In generale, se esiste la possibilità che la variabile possa effettivamente essere nullo nel prodotto finale, l'ultima versione è quella da utilizzare. Potresti fare un trattamento speciale lì o semplicemente sollevare un'eccezione come hai fatto tu.

+1

In realtà, il 2 ° e il 3 ° metodo usano l'analisi statica per provare a dimostrarlo vero in fase di compilazione. –

+0

@Anon: Ma l'analizzatore statico non sarà in grado di catturare tutte le eccezioni null in fase di compilazione ... cosa succede se uno scivola via? Alza un'eccezione, crash, non fare nulla o cosa? – mpen

+1

@ Ralph: se l'analizzatore statico non è in grado di dimostrare qualcosa in entrambi i modi (non può dimostrare che il contratto fallirà in alcuni casi, ma non può dimostrarlo sempre corretto) mostrerà un avviso di compilazione (non un errore) e sostituirlo con un'asserzione. –

Problemi correlati