Inferenza da tipo generico domanda
Domanda
Suppongo che questo è più di uno sproloquio pubblico, ma perché non posso ottenere C # di dedurre il tipo di mia Id?
public EntityT Get<EntityT>(IdT id) where EntityT : EntityObject<IdT>
e EntityObject definito con un GUID come Id come segue:
public Foo : EntityObject<Guid>
che eredita dalla classe astratta EntityObject definito come segue:
public abstract class EntityObject<IdT>
{
public IdT id { get; set; }
}
L'utilizzo del metodo get sarebbe la seguente:
IRepository repository = new Repository();
var hydratedFoo = repository.Get<Foo>(someGuidId);
a cura di fornire ulteriori chiarimenti.
Soluzione
E 'difficile da dire, dato che hai dato solo due dichiarazioni, non come si sta utilizzando loro. IDT è un altro parametro tipo da qualche parte? (Se fosse TId
, che sarebbe suggeriscono che è - ma il fatto che si sta utilizzando EntityT
per un altro parametro di tipo, contrario alle convenzioni, suggerisce che forse IdT
è così ...)
Ora, supponendo IdT
è in realtà Guid
nel tuo caso, come dovrebbe il compilatore di lavoro che si intende Foo
? Ci potrebbero essere altri tipi derivanti da EntityObject<Guid>
.
In breve, non avete ci ha dato informazioni sufficienti per dire nulla di certo, ma sembra che tu sei fondamentalmente richieste irragionevoli sul compilatore.
EDIT: Ok, ecco la mia ipotesi a quello che hai, utilizzando le normali convenzioni di denominazione:
public interface IRepository
{
TEntity Get<TEntity, TId>(TId id) where TEntity : EntityObject<TId>
}
public abstract class EntityObject<TId>
{
public IdT id { get; set; }
}
public class Foo : EntityObject<Guid> {}
Si vuole fare:
IRepository repository = GetRepositoryFromSomewhere();
Foo foo = repository.Get<Foo>(someGuid);
considerando che attualmente si deve fare:
Foo foo = repository.Get<Foo, Guid>(someGuid);
Sì, il compilatore sta rendendo leggermente di più per voi di quanto necessario. Un intero 6 personaggi extra, per il bene di mantenere il linguaggio più semplice e le regole di inferenza di tipo più facile da capire.
In sostanza tipo inferenza è un tutto o niente vicenda - o tutti parametri di tipo vengono dedotti o nessuno di essi è. Che mantiene le cose semplici, come non c'è bisogno di capire quali sono stati specificati e quali non lo sono. Questo è parte del problema, e l'altra parte è che si può solo esprimere i vincoli sui parametri di tipo del metodo - non si può avere:
class Repository<TEntity>
{
TEntity Get<TId>(TId id) where TEntity : EntityObject<TId>
}
perché è vincolante TEntity
, non TId
. Ancora una volta, questo genere di cose fa inferenza di tipo più semplice.
Ora potrebbe potenzialmente scrivere:
Foo foo = repository.Get(someGuid).For<Foo>();
con un metodo adeguato Get
e un'interfaccia supplementare. Penso che mi piacerebbe personalmente preferisco utilizzare solo Get<Foo, Guid>
però.
Altri suggerimenti
Una dichiarazione come
public EntityT Get<EntityT>(IdT id) where EntityT : EntityObject<IdT>
richiede che IDT è un tipo concreto. Se si vuole parametrizzare IDT così, avresti bisogno di usare
public EntityT Get<EntityT, IdT>(IdT id) where EntityT : EntityObject<IdT>
Ma che probabilmente non è quello che ci vuole.
Questo è il motivo per cui ho tutti ma rinunciato a tipi di chiave generici con soggetti generici. Non riuscivo a capire come ottenere i miei soggetti ad avere tipi di chiave generiche senza cospargendo i due in tutto il luogo. Ora ho optato per chiavi intere (che è quello che ho comunque dappertutto), ma ci si sente male.
Se la firma del metodo si presentava così:
public TEntity Get<TEntity, TId>(TId id) where TEntity : EntityObject<TId>
Il compilatore avrebbe qualcosa con cui lavorare ...
È quindi chiamare ottenere con qualcosa del tipo:
EDIT (mi sbagliavo): prodotto p = Get (id);
Product p = Get<Product, Guid>(id);
di Jon inchiodato questa risposta con il suo posto sulla parte superiore quindi mi zitto e strisciare indietro nel mio buco.