2014-09-11 10 views
11

Ho appena provato a utilizzare Code Contracts e non vedo alcun reale vantaggio rispetto a if statement.Codice Contratto o se dichiarazione?

Considerare quanto segue.

private static void BindClassesToInterfacesByConvention(string classesEndingWith 
    , string interfacesEndingwith) { 
    Contract.Requires<ArgumentNullexception>(
     string.IsNullOrWhiteSpace(classesEndingWith) 
     , "classesEndingWith"); 

    Contract.Requires<ArgumentNullException>(
     string.IsNullOrWhitespace(interfacesEndingWith) 
     , "interfacesendingWith"); 

    ... 
} 

trovo modo più confuso che semplicemente utilizzando un codice if statement

private static void BindClassesToInterfacesByConvention(string classesEndingWith 
    , string interfacesEndingwith) { 
    if (string.IsNullOrWhiteSpace(classesEndingWith)) 
     throw new ArgumentNullException("classesEndingWith"); 

    if (string.IsNullOrWhitespace(interfacesEndingWith)) 
     throw new ArgumentNullException("interfacesendingWith"); 

    ... 
} 

Contratti si suppone di avvertirmi in fase di compilazione che un contratto viene violato. Quindi, mi aspettavo di ricevere un errore o un avvertimento quando ho scritto quanto segue.

BindClassesToInterfacesByConvention(null, null); 

E non è successo niente, tutto è stato compilato correttamente e non è apparso né un errore né un messaggio di avviso.

In questo scenario, ritengo sia preferibile continuare con lo it statement. O forse era un uso ingiusto di Code Contracts?

+3

Ci sono più vantaggi per i Contratti di codice che solo la sintassi. In realtà sono elencati in primo piano nella sezione [Documenti sui contratti di licenza] (http://msdn.microsoft.com/en-us/library/dd264808 (v = vs.110) .aspx). L'analisi statica è un affare particolarmente importante e molto difficile da ottenere analizzando le dichiarazioni di "se". –

+0

"avvertimi al momento della compilazione" ... quello era anche il mio equivoco; ma si è scoperto che è effettivamente un programma separato (Vs addon) che analizza il tuo codice e richiede un po 'di tempo per farlo. –

risposta

4

Code Contracts sono una grande idea deluso da utensili che non è abbastanza Là. In primo luogo, per fare in modo che le eccezioni effettivamente vengano lanciate, è necessario installare le estensioni giuste in Visual Studio e/o configurare le impostazioni corrette sul progetto. Molto divertente se si dispone di test unitari basati sui contratti di codice che generano eccezioni in fase di esecuzione e li eseguono su un server di build.

Tuttavia, è importante capire che il vero scopo dei Contratti di Codice non è solo quello di generare eccezioni. Abilita l'analisi del codice statico (se lo accendi), che quando abilitato può essere in grado di darti un errore in fase di compilazione - ma richiede molto lavoro per applicarlo praticamente ovunque in modo che sia statico analisi del codice per funzionare davvero. Credo che sia lo scenario che stai cercando di testare? In tal caso, ti suggerisco di guardare l'impostazione dei contratti in codice per il tuo progetto per assicurarti di aver abilitato tutto il controllo del codice statico (renderà la tua build piuttosto lunga).

Inoltre, e soprattutto, i contratti di codice consentono di comunicare l'intento ai chiamanti dei propri metodi; Intellisense riprenderà le condizioni che hai specificato (a condizione di installare le estensioni corrette). L'informazione sui contratti di codice può anche essere aggiunta automaticamente al file XML che può accompagnare gli assembly, che consentirà quindi agli utenti di terze parti del tuo assembly di conoscere le tue esigenze quando scrivono il loro codice, oltre a permetterti di includere queste informazioni in file di aiuto costruiti con Sandcastle, ecc.

È una buona idea, solo che non è ancora completamente implementata negli strumenti, così da ottenere un comportamento divertente una volta ogni tanto. Personalmente ho praticamente smesso di usarli per il momento.

3

Si sta specificando un metodo che richiede suoi argomenti da null o spazi vuoti, quindi passando null. Il contratto è soddisfatto. Ecco perché non hai ricevuto alcuna violazione del contratto. (Requires() richiede l'eccezione quando la condizione restituisce false, non vera)

Inoltre, anche se si corregge il contratto, non si dovrebbe generare ArgumentNullException se il valore del parametro è una stringa non nulla che non contiene caratteri o solo caratteri bianchi. In tal caso dovresti lanciare un ArgumentException.

farei questo:

private static void BindClassesToInterfacesByConvention(string classesEndingWith 
    , string interfacesEndingwith) { 
    Contract.Requires<ArgumentNullException>(classesEndingWith != null 
     , "classesEndingWith"); 

    Contract.Requires<ArgumentException>(!string.IsNullOrWhiteSpace(classesEndingWith) 
     , "classesEndingWith"); 

    Contract.Requires<ArgumentNullException>(interfacesEndingWith != null 
     , "interfacesEndingWith"); 

    Contract.Requires<ArgumentException>(!string.IsNullOrWhiteSpace(interfacesEndingWith) 
     , "interfacesEndingWith"); 

    ... 
} 

Per scaricare gli strumenti di analisi Code Contracts, tra cui l'integrazione di Visual Studio, visitare http://visualstudiogallery.msdn.microsoft.com/1ec7db13-3363-46c9-851f-1ce455f66970

+0

Ho corretto il mio codice per applicare le modifiche suggerite, e ancora, non succede nulla quando compilo. –

+0

@WillMarcouiller hai installato l'estensione VS dei Contratti di codice e i contratti sono abilitati nella pagina delle proprietà del progetto? –

+0

@WillMarcouiller hai impostato le opzioni di controllo statico nella scheda dei contratti di codice delle proprietà del progetto? Vedere questo articolo per un'immagine non aggiornata che dovrebbe essere comunque utile: http://msdn.microsoft.com/en-us/magazine/hh148151.aspx – phoog

1

Questa è una risposta soggettiva, ma direi che la dichiarazione reale qui è: "Ho solo cercato di utilizzare contratti di codice, e non vedo reali vantaggi nel corso di un test Unit"

Per esempio:

private void Foo(string something) 
{ 
    Contract.Requires<ArgumentNullException>(something != null, "something"); 
} 

è equivalente (test NUnit):

void Foo(string something) 
{ 
    if (something == null) 
     throw new ArgumentNullException(); 
} 

[Test] 
[ExpectedException(typeof(ArgumentNullException))] 
void foo_throws_exception_with_null_param() 
{ 
    Foo(null); 
} 

che è meglio? Bene dalla mia (limitata) esperienza l'addon di analisi statica per VS è piuttosto lento. Se hai effettuato una chiamata a foo con una variabile nulificata esplicita, la raccoglierà. Ma non raccoglierà i null caricati dinamicamente e li invierà a foo durante l'iterazione dell'utente.

D'altra parte, se si dispone di un'istruzione if e un test di unità per assicurarsi che Getti un'eccezione ArgumentNullException, allora si sa che l'eccezione verrà lanciata; e puoi gestirlo nell'ambiente run-time ... puoi testare qualsiasi cosa che usi Foo per assicurarti che gestisca l'eccezione.

Assicurarsi che il controllo esplicito sia molto veloce con NUnit. Lo svantaggio del test unitario sta iniziando con i test. Quindi la mia opinione è che col tempo risparmierai più tempo essendo esplicito, facendo test unitari e assicurandoti che la tua applicazione possa gestire se vengono lanciate queste eccezioni ... ti costerà ancora di più per iniziare a configurarlo.

+0

'Ma non preleverà i valori nulli caricati dinamicamente e invierà a foo durante l'iterazione dell'utente. "Lo farà, in realtà. Ecco perché 'Contract.Ensures' è importante, perché puoi dichiarare che alcuni metodi non restituiranno mai nulla, e i contratti di codice prelevano queste informazioni per dedurre cosa può accadere in quei casi. – julealgon

0

Sì, i Contratti di codice ti avvisano al momento della compilazione che un contratto viene violato se attivi il controllo statico. Ha dimostrato che i componenti aggiuntivi del Contratto di codice (Code Contracts for .NET) funzionano solo su Visual Studio 2013 o versioni precedenti, ma non su Visual Studio 2015 o 2017.

su Visual Studio 2013: enter image description here

su Visual Studio 2015, possiamo vedere le informazioni di errore dalla finestra di output, ma non nella finestra Elenco errori. Questo bug era già stato registrato e corretto, ma può ancora essere riproito. Warnings and messages from static contract checking don't appear in the VS2015 error list enter image description here


Ultimo aggiornamento:
Installare l'ultima Contracts.devlab9ts.msi (attualmente, è solo versione RC) risolverà il problema in Visual Studio 2015. DotNet CodeContracts v.1.10.20606.1-rc2 enter image description here