2012-08-16 16 views
14

¿Existe alguna forma mejor de escribir esto? Como una clase quizás, en lugar de dos.Tipos genéricos opcionales

using System; 

namespace SnippetTool.Repositories 
{ 
    public abstract class ARepository<TProvider> where TProvider : class 
    { 
     protected TProvider Provider { get; set; } 

     protected ARepository(TProvider provider) 
     { 
      if (provider == null) 
       throw new ArgumentNullException("provider"); 

      Provider = provider; 
     } 
    } 

    public abstract class ARepository<TProvider, TValidator> : ARepository<TProvider> where TProvider : class where TValidator : class 
    { 
     protected TValidator Validator { get; set; } 

     protected ARepository(TProvider provider, TValidator validator) : base(provider) 
     { 
      Validator = validator; 
     } 
    } 
} 
+4

Depende de lo que quiere lograr – Magnus

+0

Quiero lograr que el TValidator sea opcional. – CaffGeek

+1

Wow ... 3 votos cercanos? CERO explicaciones. – CaffGeek

Respuesta

11

No creo que lo puede hacer como una clase, en la actualidad, por lo general lo que trato de hacer en esta situación es crear la clase más general (la que lleva los argumentos más genéricos) para tener toda la lógica, luego haga que las más específicas sean subclases que predeterminan esos tipos.

Por ejemplo, digamos que estamos escribiendo un traductor que traduce de un tipo de valor a otro, así como un Dictionary pero también tiene valores por defecto, etc.

Podríamos definir esto como:

public class Translator<TKey, TValue, TDictionary> where TDictionary : IDictionary<TKey, TValue>, new(); 
{ 
    private IDictionary<TKey, TValue> _map = new TDictionary(); 
    ... 
} 

Ésta es mi caso genérico, que puede tener cualquier implementación de IDictionary, pero decir que queremos una versión más sencilla que siempre utiliza Dictionary si no se especifica, podríamos hacer:

public class Translator<TKey, TValue> : Translator<TKey, TValue, Dictionary<TKey, TValue>> 
{ 
    // all this does is pass on the "default" for TDictionary... 
} 

De esta manera, puedo hacer:

// uses Dictionary<int, string> 
var generic = new Translator<int, string>(); 

// uses SortedDictionary instead 
var specific = new Translator<int, string, SortedDictioanry<int, string>>(); 

Así, en su caso, tal vez su genérico siempre tiene una propiedad TValidator, pero ha de pagar (tal vez para siempre volver true en su forma más genérica?

Por ejemplo, tal vez usted tiene una definición de un defecto validador (digamos llamada DefaultValidator) se podría revertir sus definiciones para que el más genérico (la que tiene parámetros de tipo más genérico) tiene toda la lógica y las especializaciones (menor número de parámetros de tipo) son sólo subclases que incumplen esos tipos adicionales:

using System; 

namespace SnippetTool.Repositories 
{ 
    public class DefaultValidator 
    { 
     // whatever your "default" validation is, may just return true... 
    } 

    public abstract class ARepository<TProvider> : ARepository<TProvider, DefaultValidator> 
     where TProvider : class 
    { 
     protected ARepository(TProvider provider) : base(provider, new DefaultValidator()); 
     { 
     } 

     // needs no new logic, just any specialized constructors... 
    } 

    public abstract class ARepository<TProvider, TValidator> 
     where TProvider : class 
     where TValidator : class 
    { 
     public TValidator Validator { get; set; } 

     protected ARepository(TProvider provider, TValidator validator) 
     { 
      Provider = provider; 
      Validator = validator; 
     } 

     // all the logic goes here... 
    } 
} 

ACTUALIZACIÓN: Sí, en base a su comentario, si el TValidator es un add-on (y no algo defecto), entonces superponiéndolo como lo hiciste es apropiado.

+0

El problema es que no quiero un TValidator en algunos casos, no es el predeterminado, simplemente no lo quiero. Pero SIEMPRE necesito un TProvider. – CaffGeek

+1

@Chad: Entonces tu código es una buena manera de hacerlo, mi único consejo sería tratar de que una de las clases sea lo más clara posible para evitar una lógica duplicada. –

+0

Gracias, eso confirma lo que pensaba. – CaffGeek