2012-06-14 6 views
5

Ecco la classe generica con cui sto lavorando:C# Calcestruzzo override classe generica

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} 
} 

Ora sto cercando di modificare di tanto in tanto il comportamento dei metodi quando t: un tipo specifico. È qualcosa come il seguente possibile? Questo particolare tentativo restituisce un errore (Errore 5: le dichiarazioni parziali di "Repository" devono avere gli stessi nomi dei parametri di tipo nello stesso ordine).

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: Repository ...', e segnare i metodi augmentible come virtual/esclusione delle classi di base/bambini, rispettivamente. –

+0

@Anthony: perché non postarlo come risposta? (Che stavo per postare = P) – benjer3

risposta

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

La mia obiezione a questa soluzione è che è necessario instradare esplicitamente 'nuovo BarRepository()'. Se chiami "nuovo repository ()", ottieni l'implementazione generica (cioè errata). Dal momento che i repository sono già stati creati e consumati attraverso il mio codebase, preferirei non dover nascondere l'instanciazione in una fabbrica. – daveharnett

+0

Ovviamente questo codice richiede che i metodi siano esposti come pubblici per soddisfare l'interfaccia e necessitino di modificatori di sovrascrittura/virtuale nella base/figlio per poter utilizzare i comportamenti in modo polimorfico. –

+0

@daveharnett, per utilizzare al meglio il modello di repository, il codice o la logica che dipende dal repository dovrebbero essere codificati per l'interfaccia anziché l'implementazione. Quel codice, quindi, guarderebbe 'IRepository ', e quindi non avrebbe bisogno di cambiare. Sebbene tu abbia ragione, qualsiasi codice incaricato di creare le implementazioni concrete dovrebbe essere aggiornato. –

0

Nome vostra classe RepositoryBase Repository e fare metodi di interfaccia virtuale. li implementa in modo generale all'interno della classe RepositoryBase, ma poiché hai contrassegnato i metodi come virtuali sarai in grado di sovrascrivere le funzionalità nelle tue classi derivate il tuo codice sarà simile a questo.

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} 
    } 

se u bisogno di un po 'di logica personalizzata da eseguire per il metodo di aggiornamento per barra degli oggetti semplicemente creare classe derivata Nome esso BarRepository e metodo di aggiornamento override della classe Repositorybase qui u possibile implementazione di base di chiamata o semplicemente di processo con il suo propria logica

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

Idem la mia risposta a roken. Otterrà il lavoro, ma renderà il consumo più difficile. – daveharnett

+0

Cosa intendi con questo? –

+0

Intendevo dire che devi istanziare 'new BarRepository()' esplicitamente. Se chiami "nuovo repository ()", ottieni l'implementazione generica (cioè errata). Idealmente stavo cercando una soluzione che sarebbe stata nascosta dal codice di creazione del repository. – daveharnett

0

come una risposta diretta alla sua domanda: la cosa più vicina possibile a quello che hai mostrato sta controllando il valore effettivo del T in fase di esecuzione. Nel vostro metodo Add, è possibile scrivere qualcosa di simile:

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

Si noti che questo potrebbe non essere molto buono in termini di prestazioni, in particolare se si dispone di più di uno o due di questi tipi speciali che si desidera trattare in modo diverso.

Oltre a ciò, l'unica soluzione è una sottoclasse che specifica l'argomento di tipo effettivo per la classe base, come indicato nelle altre risposte.

+0

Grazie. Prestazioni a parte, questo sarebbe molto complicato se ci sono più di alcuni casi speciali. – daveharnett

+0

@daveharnett: Non necessariamente; in tal caso, potresti voler usare un oggetto 'Dictionary ' of 'Handler' (una tua classe) che esegua azioni specifiche del tipo. In questo modo, sono fondamentalmente solo tre o quattro righe di codice (probabilmente meno con un metodo di estensione) in ciascun metodo che richiede un trattamento speciale. –

0

utilizzare un metodo di estensione:

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