Domanda

Ok, quindi ho una classe astratta chiamata Product. Ho 3 tabelle chiamate Articoli, Kit e Pacchetti che implementano il Prodotto. Il prodotto ha una proprietà pubblica che espone la chiave primaria dell'oggetto.

Detto questo, ho un modulo in cui passo un prodotto. Vorrei estrarre quel prodotto da un nuovo datacontext senza dover scrivere un grande interruttore che rifletta il suo tipo per ottenere la sua tabella corretta.

Volevo fare qualcosa del genere, ma il cast non accetterà foo.

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

o questo:

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

Soluzione 2

Grazie a Mr. Skeet un brillante membro del mio team ha sottolineato la seguente soluzione.

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

Mi dispiace perdere tempo. Per favore, non buttare la spazzatura nel mio dispiacere John. = OD

Altri suggerimenti

No, perché l'argomento tipo deve essere noto in fase di compilazione per apparire nel codice sorgente.

Puoi rendere BuilderInclusionsForm generico nel tipo di prodotto oppure scrivere un metodo generico come questo:

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

e quindi invocalo con la riflessione:

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

(Ovviamente è possibile memorizzare nella cache la forma aperta del metodo.)

Non è carino, ma dovrebbe funzionare. Ho il sospetto che sarebbe meglio rendere generico BuilderInclusionsForm generico, ma potresti sempre avere una classe helper:

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

che ti permetterebbe di usare l'inferenza del tipo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top