2012-06-14 8 views
5

Ésta es la clase genérica estoy trabajando con:C# anulación de hormigón de clase genérica

public interface IRepository<T> where T : EntityObject 
{ 
    RepositoryInstructionResult Add(T item); 
    RepositoryInstructionResult Update(T item); 
    RepositoryInstructionResult Delete(T item); 
} 
public class Repository<T> : IRepository<T> where T : EntityObject 
{ 

    RepositoryInstructionResult Add(T item) 
    { //implementation} 
    RepositoryInstructionResult Update(T item); 
    { //implementation} 
    RepositoryInstructionResult Delete(T item); 
    { //implementation} 
} 

Ahora estoy mirando de vez en cuando para alterar el comportamiento de los métodos cuando t: un tipo específico. ¿Es posible algo como lo siguiente? Este intento particular da un error (Error 5: las declaraciones parciales de 'Repositorio' deben tener los mismos nombres de parámetros de tipo en el mismo orden).

public class Repository<Bar> //where Bar : EntityObject 
{ 
    RepositoryInstructionResult Add(Bar item) 
    { //different implementation to Repository<T>.Add() } 
    //other methods inherit from Repository<T> 
} 
+2

'BarRepository: Repositorio ...', y marcar los métodos augmentible como virtual/override en las clases base/niño, respectivamente. –

+0

@Anthony: ¿Por qué no publicar eso como respuesta? (Que estaba a punto de publicar = P) – benjer3

Respuesta

4
public class BarRepository : Repository<Bar> 
{ 
    RepositoryInstructionResult Add(Bar item) 
    { //different implementation to Repository<T>.Add() } 
    //other methods inherit from Repository<T> 
} 
+1

Mi objeción a esta solución es que necesitas instanciar 'nuevo BarRepository()' explícitamente. Si llama a 'new Repository ()', obtendrá la implementación genérica (es decir, incorrecta). Como los repositorios ya se están creando y consumiendo en mi base de código, prefiero no tener que ocultar la instanciación en una fábrica. – daveharnett

+0

Este código obviamente necesitaría métodos para ser expuestos como públicos a fin de cumplir con la interfaz y necesitar modificadores virtuales/anulación en la base/hijo para utilizar polimórficamente los comportamientos. –

+0

@daveharnett, para utilizar mejor el patrón de repositorio, el código o la lógica que depende del repositorio codificará la interfaz en lugar de la implementación. Ese código, entonces, estaría mirando 'IRepository ', y por lo tanto no tendría que cambiar. Aunque tiene razón, cualquier código a cargo de crear las implementaciones concretas debería actualizarse. –

0

Nombre RepositoryBase su clase repositorio y hacer que los métodos de interfaz virtual. impleméntelos de una manera general dentro de su clase RepositoryBase, pero debido a que usted marcó métodos como virtuales u podrá anular la funcionalidad en sus clases derivadas, su código se verá más o menos así.

public interface IRepository<T> where T : EntityObject 
{ 
    RepositoryInstructionResult Add(T item); 
    RepositoryInstructionResult Update(T item); 
    RepositoryInstructionResult Delete(T item); 
} 

public class Repository<T> : IRepository<T> where T : EntityObject 
{ 
    virtual RepositoryInstructionResult Add(T item) 
    { //implementation} 
    virtual RepositoryInstructionResult Update(T item); 
    { //implementation} 
    virtual RepositoryInstructionResult Delete(T item); 
    { //implementation} 
    } 

U Si necesita alguna lógica personalizada para ser ejecutados para el método de actualización para Barra de objetos simplemente cree Nombre clase derivada que BarRepository y método de actualización de sustitución de la clase Repositorybase aquí u Puede implementación base llamada o proceso que se acaba con su propia lógica

public class BarRepository : Repositorybase<Bar> 
{ 
    public override RepositoryInstructionResult Update(Bar item); 
    { 
     //Call base method if needed 
     //Base.Update(item); 

     //implement your custom logic here 
    } 
    } 
+0

Lo mismo mi respuesta a roken. Hará el trabajo, pero hará el consumo más difícil. – daveharnett

+0

¿Qué quieres decir con eso? –

+0

Quería decir que necesitas instanciar 'nuevo BarRepository()' explícitamente. Si llama a 'new Repository ()', obtendrá la implementación genérica (es decir, incorrecta). Idealmente, estaba buscando una solución que estaría oculta del código de creación del repositorio. – daveharnett

0

Como respuesta directa a su pregunta: lo más parecido posible a lo que has demostrado es la comprobación del valor real de T en tiempo de ejecución. En el método add, se puede escribir algo como esto:

if (typeof(T) == typeof(Bar)) { 
    // your Bar-specific code 
} 
// ... 

Tenga en cuenta que esto puede no ser muy bueno en términos de rendimiento, especialmente si tiene más de uno o dos de estos tipos especiales que desee para tratar diferentemente.

Aparte de eso, la única solución es una subclase que especifica el argumento de tipo real para la clase base, como se indica en las otras respuestas.

+0

Gracias. Dejando a un lado el rendimiento, esto sería muy complicado si hay más de unos pocos casos especiales. – daveharnett

+0

@daveharnett: No necesariamente; en ese caso, es posible que desee utilizar un objeto 'Dictionary ' de 'Handler' (una clase propia) que ejecuta acciones específicas de tipo. De esta manera, básicamente se trata de tres o cuatro líneas de código (posiblemente menos con un método de extensión) en cada método que necesita un tratamiento especial. –

0

utilizar un método de extensión:

public static void DoSomething(this repository<Bar> repo) 
{ 
    //your custom code goes here 
} 
Cuestiones relacionadas