2009-10-20 14 views
20

Quali approcci le persone adottano (se esistono) nella gestione dell'esplosione guard clause nelle classi? Per esempio:Clausole di protezione refactoring

public void SomeMethod<T>(string var1, IEnumerable<T> items, int count) 
{ 
    if (string.IsNullOrEmpty(var1)) 
    { 
     throw new ArgumentNullException("var1"); 
    } 

    if (items == null) 
    { 
     throw new ArgumentNullException("items"); 
    } 

    if (count < 1) 
    { 
     throw new ArgumentOutOfRangeException("count"); 
    } 

    ... etc .... 
} 

Nel progetto che sto attualmente lavorando su Ci sono molte classi che hanno un simile insieme di clausole di guardia sui metodi pubblici.

Sono a conoscenza dei Contratti di codice .NET 4.0, tuttavia non è un'opzione per il nostro team al momento.

risposta

39

un sacco di progetti che ho visto usare un Guard classe statica.

public static class Guard { 
    public static void ArgumentIsNotNull(object value, string argument) { 
     if (value == null) 
      throw new ArgumentNullException(argument); 
    } 
} 

Rende il codice molto più pulito, secondo me.

Guard.ArgumentIsNotNull(arg1, "arg1"); 
+1

Stavo semplicemente postando la stessa cosa. L'unico problema è che pone questo metodo all'inizio della traccia dello stack rispetto al metodo di origine in alto, non che sia così enorme. Questo schema potrebbe ovviamente essere utilizzato per diversi tipi per controllare un intervallo di valori, ecc ... –

+0

Sì, questo è l'unico problema che ho mai avuto con questo.Anche se è abbastanza facile trovare il metodo di chiamata originale. –

+1

Questa è essenzialmente la stessa cosa delle classi che imitano i contratti di codice. –

5

Se non si vuole imboccare la strada Code Contracts, un modo per semplificare è quello di rimuovere le parentesi graffe:

public void SomeMethod<T>(string var1, IEnumerable<T> items, int count) 
{ 
    if (string.IsNullOrEmpty(var1)) 
     throw new ArgumentNullException("var1"); 

    if (items == null) 
     throw new ArgumentNullException("items"); 

    if (count < 1) 
     throw new ArgumentOutOfRangeException("count"); 

    ... etc .... 
} 

Oltre a questo, ci sono alcuni modi che si possono simulare Code Contracts , se la vostra obiezione è che .Net 4.0 non è il prime time ancora:

http://geekswithblogs.net/Podwysocki/archive/2008/01/22/118770.aspx

+0

Per l'amor di Dio, non farlo! Se le affermazioni senza parentesi graffe sono un ottimo modo per causare problemi a se stessi lungo la strada. – EricRRichards

+1

@EricRRichards: * [scrollando le spalle] * Francamente, se i programmatori non riescono a mantenere il loro codice dritto senza parentesi graffe (in particolare codice non comune come questo), probabilmente dovrebbero tornare a scuola. –

3

Un approccio per la riduzione (non completamente rimuovere) il numero delle clausole di guardia è capire la causa della loro esistenza. Molto spesso, si evita che ci salvaguardi da valori validi per il tipo dell'argomento, ma non validi per il metodo che li accetta. In altre parole, il metodo è definito su un sottoinsieme del dominio definito dal tipo di argomento.

La soluzione a questa categoria di casi è provare a definire un sottotipo (ad esempio un'interfaccia più restrittiva) e accettare tale tipo come argomento. È possibile trovare un esempio illustrativo in questo articolo: Why do We Need Guard Clauses?

Naturalmente questa tecnica non si applica a tutti i casi. Tutti i tipi di riferimento consentono almeno riferimenti null. Di conseguenza, la maggior parte dei nostri metodi sarà definita su una parte del dominio, che a sua volta richiede una clausola di salvaguardia contro null.

Ma sul lato positivo, questa tecnica aiuta a far crescere la consapevolezza dei metodi che ricevono argomenti che sono più generali del desiderato. Plumbing that hole aiuta a migliorare il design in generale.