2009-01-13 7 views
3

Ok, donc j'ai une classe abstraite appelée produit. J'ai 3 tables appelées Items, Kits et Packages qui implémentent le produit. Le produit possède une propriété publique qui expose la clé primaire de l'objet.Obtenir l'entité de la table à l'aide de la réflexion de type abstrait

Cela dit j'ai une forme où je passe un produit. Je voudrais tirer ce produit hors d'un nouveau contexte de données sans devoir écrire un gros commutateur reflétant son type pour obtenir sa table appropriée.

Je voulais faire quelque chose comme ça, mais le bit cast n'acceptera pas foo.

public BuilderInclusionsForm(Product p) : this() 
     {    
      Type foo = p.GetType(); 
      product = db2.GetTable(p.GetType()).Cast<foo>().SingleOrDefault(a => 
       a.ProductID == p.ProductID); 

ou ceci:

public BuilderInclusionsForm(Product p) : this() 
     {    
      Type foo = p.GetType(); 
      product = db2.GetTable(p.GetType()).OfType<foo>().SingleOrDefault(a => 
       a.ProductID == p.ProductID); 

Répondre

3

Merci à M. Skeet un membre brillant de mon équipe a souligné la solution suivante.

public BuilderInclusionsForm(Product p) : this() 
{ 
    IEnumerable<Product> ps = db2.GetTable(p.GetType()).Cast<Product>(); 
    product = ps.SingleOrDefault(a => a.ProductID == p.ProductID); 
} 

Désolé de perdre votre temps. S'il vous plaît ne pas ramasser les ordures mon désolé John. = oD

5

Non, parce que l'argument de type doit être connu à la compilation d'apparaître dans le code source.

Vous pouvez soit faire BuilderInclusionsForm générique dans le type de produit ou écrire une méthode générique comme ceci:

private static T FindProduct<T>(T product) where T : Product 
{ 
    return db2.GetTable(typeof(T)) 
        .OfType<T>() 
        .SingleOrDefault(a => a.ProductID == p.ProductID); 
} 

puis invoquer avec la réflexion:

public BuilderInclusionsForm(Product p) : this() 
{    
    MethodInfo method = typeof(BuilderInclusionsForm).GetMethod("FindProduct", 
     BindingFlags.Static | BindingFlags.NonPublic); 
    MethodInfo concrete = method.MakeGenericMethod(new Type[] { p.GetType() }); 
    product = (Product) concrete.Invoke(null, new object[] { p }); 
} 

(Il est évident que vous pouvez mettre en cache la forme ouverte de la méthode.)

Pas sympa, mais cela devrait fonctionner. Je soupçonne que ce serait plus agréable de simplement faire BuilderInclusionsForm générique si - vous pouvez toujours avoir une classe d'aide:

public static class BuilderInclusionsForm 
{ 
    public static BuilderInclusionsForm<T> Create<T>(T product) where T : Product 
    { 
     return new BuilderInclusionsForm<T>(product); 
    } 
} 

qui vous permettra d'utiliser l'inférence de type.

+0

Au risque de paraître idiot. La forme n'est pas statique, cela semble compliquer les choses. Classe publique partielle BuilderInclusionsForm: Office2007Form De plus, il semble vouloir un type de retour pour FindProduct. – Echostorm

+0

Oups - correction de FindProduct. Si vous ne pouvez pas faire de BuilderInclusionsForm un type générique, l'appel de méthode générique peut être la meilleure solution. –

+0

Merci. Je rencontre toujours des problèmes car FindProduct ne peut pas être statique car il doit avoir le datacontext et le productID d'origine, je pense que cela cause un nullref sur le bit MakeGenericMethod. – Echostorm

Questions connexes