Diciamo che vogliamo dichiarare
interface IPersonRepository : IRepository<Person> { }
che avrebbe richiesto che ci sia una generica interfaccia con un tipo di parametro IRepository<EntityType>
.
interface IRepository<EntityType> where EntityType : Entity<KeyType>
{
EntityType Get(KeyType id);
}
Alla fine della prima linea, si fa riferimento a una cosa chiamata KeyType
, che non è stato dichiarato né definito. Non esiste un tipo chiamato "KeyType".
Questo potrebbe funzionare se:
interface IRepository<EntityType> where EntityType : Entity<int>
{
EntityType Get(int id);
}
O questo:
interface IRepository<EntityType> where EntityType : Entity<string>
{
EntityType Get(string id);
}
Ma non si può avere entrambe le definizioni contrastanti allo stesso tempo, naturalmente. Ovviamente, non sei contento di questo, perché vuoi essere in grado di definire la tua interfaccia IRpository in modo che funzioni anche con altri tipi di chiavi.
Bene, è possibile, se si rendono generico nel tipo di chiave:
interface IRepository<KeyType, EntityType> where EntityType : Entity<KeyType>
{
EntityType Get(KeyType id);
}
Esiste un approccio alternativo:
interface IRepository<KeyType>
{
EntityType<KeyType> Get(KeyType id);
}
Ora è possibile definire
class PersonRepository : IRepository<int>
{
public EntityType<int> Get(int id) { ... }
}
Ovviamente, non ne saresti felice, perché vorresti affermare che il metodo Get deve restituire un Person
, non solo qualsiasi Entity<int>
.
L'interfaccia generica con due parametri di tipo nell'unica soluzione. E infatti, c'è una relazione richiesta tra loro, come espressa nel vincolo. Ma non c'è ridondanza qui: specificare int
per il parametro type non contiene abbastanza informazioni.
Se diciamo
class PersonRepository : IRepository<int, Person>
{
public Person Get(int id) { ... }
}
V'è infatti la ridondanza: specificando il parametro di tipo int
è ridondante se è già stato specificato il parametro type Person
.
Sarebbe possibile ottenere op con una sintassi che consenta di dedurre il KeyType. Ad esempio, Patrick Hoffman ha suggerito:
class PersonRepository : IRepository<EntityType: Person>.
{
public Person Get(int id) { ... }
}
Mentre teoricamente possibile, temo che questo sarebbe aggiungere un sacco di complessità alla specifica del linguaggio e il compilatore, per molto poco guadagno. In effetti, c'è qualche guadagno? Sicuramente non staresti salvando le battute! Confronta questi due:
// current syntax
class PersonRepository : IRepository<int, Person>
{
public Person Get(int id) { ... }
}
// proposed syntax
class PersonRepository : IRepository<EntityType: Person>
{
public Person Get(int id) { ... }
}
Il linguaggio è quello che è, e non sembra troppo male per me.
Come dovrebbe essere in grado di conoscere il 'KeyType'? Puoi mostrare la sintassi completa di ciò che ti aspetti? La tua ultima definizione di interfaccia sembra non completa. –
Non penso sia possibile. Il compilatore non è abbastanza "intelligente". Non farò una risposta però perché "Non riesco a pensare a nessun modo in cui tu possa farlo" non è una prova sufficiente che non puoi. – Falanwe
Suppongo che l'ultima riga di codice dovrebbe essere l'interfaccia IPersonRepository: IRepository {...} ' –
Rawling