使用反射从抽象类型中获取表格实体

3

好的,我有一个名为Product的抽象类,与之相关的有3个表Items、Kits和Packages。这些表都是Product的实现。Product有一个公共属性,用于暴露对象的主键。

也就是说,我有一个表单,需要传递一个产品。我希望在不必写大量反射代码来获取正确的表格类型的情况下,能够从新的数据上下文中提取该产品。

我想做这样的事情,但是转换部分不接受foo。

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

或者这个:
public BuilderInclusionsForm(Product p) : this()
        {            
            Type foo = p.GetType();
            product = db2.GetTable(p.GetType()).OfType<foo>().SingleOrDefault(a => 
                a.ProductID == p.ProductID);   
2个回答

5

不行,因为类型参数必须在编译时就已知才能出现在源代码中。

你可以将BuilderInclusionsForm泛型化为产品类型,或编写一个像这样的通用方法:

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

然后使用反射调用它:

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

(显然,您可以缓存方法的打开形式。)
不太好看,但应该有效。我认为更好的做法是使BuilderInclusionsForm通用 - 您始终可以拥有一个辅助类:
public static class BuilderInclusionsForm
{
    public static BuilderInclusionsForm<T> Create<T>(T product) where T : Product
    {
        return new BuilderInclusionsForm<T>(product);
    }
}

这将允许您使用类型推断。


冒昧地说,这个表格不是静态的,这似乎让事情变得更加复杂。 public partial class BuilderInclusionsForm : Office2007Form此外,它似乎希望 FindProduct 有一个返回类型。 - Echostorm
糟糕 - 修复了FindProduct。如果您无法将BuilderInclusionsForm设置为通用类型,则通用方法调用可能是最佳选择。 - Jon Skeet
谢谢。我仍然有些困难,因为FindProduct不能是静态的,因为它需要具有数据上下文和原始产品ID,我认为这会在MakeGenericMethod部分引起nullref。 - Echostorm

3
感谢Skeet先生,我团队中一位聪明的成员指出了以下解决方案。
public BuilderInclusionsForm(Product p) : this()
{
    IEnumerable<Product> ps = db2.GetTable(p.GetType()).Cast<Product>();
    product = ps.SingleOrDefault(a => a.ProductID == p.ProductID);
}

抱歉浪费您的时间。请不要回收我的抱歉的屁股,约翰。=oD

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接