2012-10-29 9 views
6
programma

esempio riportato di seguito:Puoi spiegare questo comportamento generico e se ho una soluzione alternativa?

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace GenericsTest 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      IRetrievable<int, User> repo = new FakeRepository(); 

      Console.WriteLine(repo.Retrieve(35)); 
     } 
    } 

    class User 
    { 
     public int Id { get; set; } 
     public string Name { get; set; } 
    } 

    class FakeRepository : BaseRepository<User>, ICreatable<User>, IDeletable<User>, IRetrievable<int, User> 
    { 
     // why do I have to implement this here, instead of letting the 
     // TKey generics implementation in the baseclass handle it? 
     //public User Retrieve(int input) 
     //{ 
     // throw new NotImplementedException(); 
     //} 
    } 

    class BaseRepository<TPoco> where TPoco : class,new() 
    { 
     public virtual TPoco Create() 
     { 
      return new TPoco(); 
     } 

     public virtual bool Delete(TPoco item) 
     { 
      return true; 
     } 

     public virtual TPoco Retrieve<TKey>(TKey input) 
     { 
      return null; 
     } 
    } 

    interface ICreatable<TPoco> { TPoco Create(); } 
    interface IDeletable<TPoco> { bool Delete(TPoco item); } 
    interface IRetrievable<TKey, TPoco> { TPoco Retrieve(TKey input); } 
} 

Questo programma di esempio rappresenta le interfacce mio vero programma usa, e dimostra il problema che sto avendo (commentata in FakeRepository). Vorrei che questa chiamata al metodo fosse gestita genericamente dalla classe base (che nel mio esempio reale è in grado di gestire il 95% dei casi dati), consentendo di eseguire l'override nelle classi figlie specificando esplicitamente il tipo di TKey. Non sembra che importi i vincoli dei parametri che uso per IRetrievable, non riesco mai a far sì che la chiamata al metodo passi alla classe base.

Inoltre, se qualcuno può vedere un modo alternativo per implementare questo tipo di comportamento e ottenere il risultato che alla fine sto cercando, sarei molto interessato a vederlo.

Pensieri?

risposta

3

Che il codice non viene compilato per la stessa ragione per cui questo esempio più semplice non compila:

public interface IBar 
{ 
    void Foo(int i); 
} 

public class Bar : IBar 
{ 
    public void Foo<T>(T i) 
    { 
    } 
} 

I metodi semplicemente non hanno la stessa firma. Sì, è possibile chiamare someBar.Foo(5) e risolvere T a int, ma il fatto rimane che Foo in Bar non ha ancora la stessa firma di un metodo che in realtà utilizza uno int come parametro.

È inoltre possibile dimostrare ciò con un metodo non generico e generico nel tipo; ciò non si traduca in un errore relativo ambiguità:

public class Bar : IBar 
{ 
    public void Foo(int i) 
    { 

    } 
    public void Foo<T>(T i) 
    { 
    } 
} 

Per quanto riguarda in realtà risolvere il tuo problema, si potrebbe fare questo:

class FakeRepository : BaseRepository<User>, ICreatable<User>, IDeletable<User>, IRetrievable<int, User> 
{ 
    public User Retrieve(int input) 
    { 
     return Retrieve<int>(input); 
    } 
} 

Ciò significa che FakeRespository ha sia una generica e non generico versione di Retrieve, ma alla fine tutte le chiamate vengono comunque indirizzate alla versione generica.

1

Il compilatore ha idea di cosa TKey è in BaseRepository e non ha modo di rapportarsi a questo IRetreivable (notare che i metodi generici non hanno la stessa firma quelli non generici).

Penso che si desidera qualcosa di più in questa direzione, con la classe di base facendo l'ereditare interfaccia e specificare anche il TKey:

class FakeRepository : BaseRepository<int, User> 
{ 
} 

class BaseRepository<TKey, TPoco> : ICreatable<TPoco>, IDeletable<TPoco>, IRetrievable<TKey, TPoco> where TPoco : class,new() 
{ 
    public virtual TPoco Create() 
    { 
     return new TPoco(); 
    } 

    public virtual bool Delete(TPoco item) 
    { 
     return true; 
    } 

    public virtual TPoco Retrieve<TKey>(TKey input) 
    { 
     return null; 
    } 
} 
+0

Una cosa da aggiungere, e sfortunatamente non l'ho inclusa nell'esempio originale, è che il mio FakeRepository può avere diverse interfacce IRetrievable definite, tutte con lo stesso TPoco, ma diversi TKey. –

Problemi correlati