2011-01-26 16 views
28

que normalmente miro argumentos del constructor de valores nulos de la siguiente manera:Comprobación de parámetros constructor para nula antes de llamar a la base

public class SomeClass(SomeArgument someArgument) 
{ 
    if(someArgument == null) throw new ArgumentNullException("someArgument"); 
} 

Pero decir que tengo una clase que hereda de otra clase:

public abstract class TheBase 
{ 
    public TheBase(int id) 
    { 

    } 
} 

public class TheArgument 
{ 
    public int TheId { get; set; } 
} 

public class TheInheritor : TheBase 
{ 
    public TheInheritor(TheArgument theArgument) : base(theArgument.TheId) 
    { 

    } 
} 

Y alguien ahora construye una instancia de TheInheritor de esta manera:

var theVar = new TheInheritor(null); 

No puedo th Se está llamando a la tinta de un modo que para comprobar null antes de base (y lanzando un NullReferenceException). Si dejo que el constructor de TheBase acepte una instancia de TheArgument, no veo cómo podría tener esta verificación de cordura. ¿Pero qué pasa si TheArgument está relacionado solo con TheInheritor y hay muchas otras clases que heredan de TheBase?

¿Alguna recomendación sobre cómo solucionar esto?

Respuesta

40

Puede hacerlo con algo como esto:

public TheInheritor(TheArgument theArgument) 
    : base(ConvertToId(theArgument)) 
{ 
} 

private static int ConvertToId(TheArgument theArgument) 
{ 
    if (theArgument == null) 
    { 
     throw new ArgumentNullException("theArgument"); 
    } 
    return theArgument.Id; 
} 

o más en general, algo como esto:

public TheInheritor(TheArgument theArgument) 
    : base(Preconditions.CheckNotNull(theArgument).Id) 
{ 
} 

donde Preconditions es una clase de utilidad en otros lugares, como este:

public static class Preconditions 
{ 
    public static T CheckNotNull<T>(T value) where T : class 
    { 
     if (value == null) 
     { 
      throw new ArgumentNullException(); 
     } 
     return value; 
    } 
} 

(Esto pierde el nombre del argumento, por supuesto, pero podrías pasarlo también si nc essary.)

+0

realizar una función de un parámetro? ¿Eso siempre estuvo en C#? Nunca lo vi antes. Pero se ve bien;) (¿o no?) –

+0

Cosas geniales. Me pregunto por qué no pensé en eso. Aprendiendo todos los días :-) +1 –

+0

Creo que me gusta el enfoque general aún mejor. Gracias Jon. –

0

Como regla general, solo me preocuparía por los parámetros que estoy usando en mi clase. Los parámetros que solo usa la clase base I pasarían directamente y dejarían que la clase se preocupara por eso.

0

Se podría llamar al constructor de base como esto (por el bien del argumento presupone -1 indica un valor no válido):

public class TheInheritor : TheBase 
    { 
     public TheInheritor(TheArgument theArgument) : base(theArgument == null ? -1 : theArgument.TheId) 
     { 
       if (theArgument == null) 
       { 
        throw new ArgumentNullException("theArgument"); 
       } 

     } 
    } 
+0

Esto permitiría que la instancia se cree en lo que se puede suponer que es un estado no válido. –

+0

@Fredrik: Correcto, cambió un poco la implementación. Pero me gusta que Jon sea mejor de todos modos. –

1

Como alternativa, se puede utilizar un Func <> para la selección ID:

public class TheInheritor : TheBase 
{ 
    public TheInheritor(TheArgument theArgument, Func<TheArgument, int> idSelector) 
     : base(idSelector(theArgument)) 
    { 
     ... 
    } 
} 

o incluso

public class TheInheritor<T> : TheBase where T : TheArgument 
{ 
    public TheInheritor(T theArgument, Func<T, int> idSelector) 
     : base(idSelector(theArgument)) 
    { 
     ... 
    } 
} 

Las excepciones caerán en su propia, así como obligará al destinatario a decidir cómo especificar el objeto Id.

Cuestiones relacionadas