Pregunta

Ok, entonces tengo una clase abstracta llamada Producto. Tengo 3 tablas llamadas Artículos, Kits y Paquetes que implementan Producto. El producto tiene una propiedad pública que expone la clave principal del objeto.

Dicho esto, tengo un formulario donde paso un producto. Me gustaría extraer ese producto de un nuevo contexto de datos sin tener que escribir un gran interruptor que refleje su tipo para obtener su tabla adecuada.

Quería hacer algo como esto, pero el bit de reparto no aceptará foo.

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

o esto:

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

Solución 2

Gracias al Sr. Skeet, un miembro brillante de mi equipo señaló la siguiente solución.

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

Perdón por perder tu tiempo. Por favor, no recojas basura, lo siento, John. = oD

Otros consejos

No, porque el argumento de tipo debe conocerse en tiempo de compilación para que aparezca en el código fuente.

Puede hacer que BuilderInclusionsForm sea genérico en el tipo de producto, o escribir un método genérico como este:

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

y luego invocarlo con reflexión:

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

(Obviamente, puede almacenar en caché la forma abierta del método).

No es agradable, pero debería funcionar. Sin embargo, sospecho que sería mejor hacer que BuilderInclusionsForm sea genérico; siempre podría tener una clase auxiliar:

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

que le permitiría utilizar la inferencia de tipos.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top