2015-03-21 16 views
7

Ad esempio, di solito non si vuole parametri in un costruttore per essere nullo, quindi è molto normale vedere qualche cosa comemodo migliore per controllare per i parametri nulli (Guardia clausole)

if (someArg == null) 
{ 
    throw new ArgumentNullException(nameof(someArg)); 
} 

if (otherArg == null) 
{ 
    throw new ArgumentNullException(nameof(otherArg)); 
} 

Lo fa ingombrare un po 'il codice.

C'è un modo per controllare un argomento di un elenco di argomenti meglio di questo?

Qualcosa come "controllare tutti gli argomenti e gettare un ArgumentNullException se qualcuno di loro è nullo e che dà gli argomenti che sono stati nulli.

Tra l'altro, per quanto riguarda reclami domanda duplicato, non si tratta di contrassegnare gli argomenti con attributi o qualcosa che è incorporato, ma ciò che alcuni chiamano Clausole di protezione per garantire che un oggetto riceva dipendenze inizializzate

+2

possibile duplicato di [Contrassegna i parametri come NOT nullable in C# /. NET?] (Http://stackoverflow.com/questions/291340/mark-parameters-as-not-nullable-in-c-net) –

+1

forse metterli tutti in un array di oggetti e scorrere su di essi utilizzando un ciclo foreach? hai bisogno di qualcosa del genere? – JoJo

+0

Di solito controlliamo i nostri parametri all'inizio del metodo come il tuo snippet di codice. Non solo per null, anche per altri comportamenti di logica aziendale. Non vedo alcun problema con questo finché non si hanno troppi parametri. Almeno puoi leggere facilmente i requisiti del tuo metodo. – Andre

risposta

8
public static class Ensure 
{ 
    /// <summary> 
    /// Ensures that the specified argument is not null. 
    /// </summary> 
    /// <param name="argumentName">Name of the argument.</param> 
    /// <param name="argument">The argument.</param> 
    [DebuggerStepThrough] 
    [ContractAnnotation("halt <= argument:null")]   
    public static void ArgumentNotNull(object argument, [InvokerParameterName] string argumentName) 
    { 
     if (argument == null) 
     { 
      throw new ArgumentNullException(argumentName); 
     } 
    } 
} 

utilizzo:

// C# < 6 
public Constructor([NotNull] object argument) 
{ 
    Ensure.ArgumentNotNull(foo, "foo"); 
    ... 
} 

// C# >= 6 
public Constructor([NotNull] object bar) 
{ 
    Ensure.ArgumentNotNull(bar, nameof(bar)); 
    ... 
} 

Il DebuggerStepThroughAttribute viene in molto utile in modo che in caso di un excpetion durante il debug (o quando allego il debugger dopo la si è verificata un'eccezione) Non rientrerò nel metodo ArgumentNotNull ma nel metodo di chiamata in cui il riferimento nullo actually è accaduto.

Sto usando ReSharper Contract Annotations.

  • Il ContractAnnotationAttribute fa in modo che non ho mai misspell l'argomento ("foo") e rinomina anche automaticamente se cambio titolo il simbolo foo.
  • Il NotNullAttribute aiuta ReSharper con l'analisi del codice. Quindi, se faccio new Constructor(null) se riceverò un avviso da ReSharper che questo porterà ad un'eccezione.
  • Se non ti piace annotare il tuo codice direttamente, puoi anche fare lo stesso con external XML-files che potresti distribuire con la tua libreria e che gli utenti possono fare riferimento opticamente nel loro ReShaprer.
8

Se hai troppi parametri nei costruttori, è meglio rivederli, ma questa è un'altra storia:

Per diminuire il numero di piastre codice di validazione molti ragazzi scrivono classi di utilità della Guardia di simile:

public static class Guard 
{ 
    public static void ThrowIfNull(object argumentValue, string argumentName) 
    { 
     if (argumentValue == null) 
     { 
      throw new ArgumentNullException(argumentName); 
     } 
    } 

    // other validation methods 
} 

(è possibile aggiungere altri metodi di validazione che potrebbero essere necessarie per quella classe Guardia).

Così ci vuole solo una riga di codice per convalidare un parametro:

private static void Foo(object obj) 
    { 
     Guard.ThrowIfNull(obj, "obj"); 
    } 
+0

Bello! compatto e può persino usare il nome di operatore :) Grazie! – SuperJMN

+1

@SuperJMN: Prego :) –

+8

Solo una nota minore, potresti anche usare l'operatore 'nameof' invece di codificare il nome dell'argomento, ad es. 'Guard.ThrowIfNull (obj, nameof (obj))' –

5

riferimenti Null sono un tipo di problemi si devono evitare. Ma non sono l'unico. Il problema è più ampio di quello, e si riduce a questo: Il metodo accetta istanze di un certo tipo, ma non può gestire tutte le istanze.

In altre parole, il dominio del metodo è maggiore dell'insieme di valori che gestisce. Le clausole di guardia vengono quindi utilizzate per affermare che il parametro effettivo non rientra in quella "zona grigia" del dominio del metodo che non può essere gestito.

Ora, abbiamo riferimenti null, come valore che è tipicamente al di fuori dell'insieme di valori accettabile. D'altra parte, spesso accade che anche alcuni elementi non nulli dell'insieme siano inaccettabili (ad es. Stringa vuota).

In tal caso, è possibile che la firma del metodo sia troppo ampia, il che indica un problema di progettazione. Ciò potrebbe portare a una riprogettazione, ad es. definendo un sottotipo, tipicamente un'interfaccia derivata, che limita il dominio del metodo e fa scomparire alcune clausole di guardia. È possibile trovare un esempio in questo articolo: Why do We Need Guard Clauses?

1

C'è un pacchetto di nuget chiamato Swissknife. Installa Swissknife dalla galleria di nuget. Fornisce molte opzioni che iniziano con il controllo nullo per gli argomenti Argument.IsNotNullOrEmpty(args,"args") sotto lo spazio dei nomi Swissknife.Diagnostics.Contracts insieme all'opzione idoim e molti altri. È possibile impostare Option<Class_Name> _someVar e quindi verificare se _someVar.IsSome or _SomeVar.IsNone. Questo aiuta anche contro le classi nullable. Spero che questo ti aiuti.

Problemi correlati