2011-04-20 93 views
0

有一个很有趣的情况,似乎无法找到任何对周围的反射,继承和泛型腹板混凝土。使用实体框架抽象类

要开始使用:

我有一个抽象基类化,可称为:

public abstract class ItemBase 
{ 
    // default properties 
} 

ItemBase就变成了我的超类的抽象实体,称为项目:

public abstract class Item 
{ 
    // some extra properties 
} 

这背后的想法是构造将继承Item的附加属性集的实体:

public partial class City : Item {} 

现在,在测试方法我想使用反射来调用通过实体的方法,并返回任何数据,在什么都形成,从方法回来。

假设,出于测试目的,我们在状态的方法,返回所有主要城市的集合:

public List<City> GetAllMajorCities() {} 

在我的存根我可能有一个测试,以获得所有城市:

List<Item> cities = this.InvokeGenericMethod<Item>("State", "GetAllMajorCities", args); 

然后InvokeGenericMethod(字符串,字符串,对象[]参数)看起来像:

public IEnumerable<T> InvokeGenericMethod<Item>(string className, string methodName, object[] args) 
{ 
    Type classType = className.GetType(); // to get the class to create an instance of 
    object classObj = Activator.CreateInstance(classType); 
    object ret = classType.InvokeMember(methodName, BindingFlags.InvokeMethod, null, classObj, args); 
} 

从理论上讲,从给出的实例中,“RET”的值应该是一个IEnumerable类型,然而,返回类型,如果加入到手表investivage,返回列表,如果我检查RET值:

if (ret is IEnumerable<T>) 

它忽略了检查。

如果我改变

public List<City> GetAllMajorCities() {} 

public List<ItemBase> GetAllMajorCities() {} 

似乎要坚持继承和允许我丢给IEnumberable。

我在这里完全难住了。

任何意见,建议,将不胜感激。

感谢,

埃里克

+0

你能重新检查你的代码吗?我觉得有一些东西混在一起。我猜你的InvokeGenericMethod不起作用。例如,className.GetType()将全部返回类型字符串。 – Achim 2011-04-20 07:23:01

+0

嗨Achim,上面的代码是一个真正的道歉,如果它有点混乱的例子。在绑定一个下拉列表时,我使用反射到类的全名,类的字符串格式的命名空间,然后将其作为一个字符串传递给我的InvokeGenericMethod。 – JadedEric 2011-04-20 10:09:10

回答

3

您是否可能使用Framework 3.5? .net 4.0中引入了泛型协变和逆变。因此,下面是不可能在Framework 3.5:

class ItemBase { } 
class Item : ItemBase { } 
class City : Item { } 

class Program 
{ 
    static void Main(string[] args) 
    { 
     IEnumerable<City> cities = new List<City>(); 
     IEnumerable<Item> items = cities; // Compile error here. IEnumerable<Item> is not a supertype of IEnumerable<City>. 
    } 
} 

注意以下(这是你要实现的目标)将不会在.NET 4.0中,即使工作:

List<Item> cities = new List<City>(); 

为什么这不正常吗?因为必须可以向List<Item>添加任意的Item。但是,显然,cities.Add(new Person());不能工作(因为cities的“真实”(=静态)类型是List<City>)。因此,List<Item>永远不可能是List<City>的超类型。

无法项目添加到一个IEnumerable,这就是为什么有IEnumerable<City>IEnumerable<Item>之间的关系亚型(但只能在.NET 4.0中,如上面提到的)。

+0

嗨Heinzi。谢谢你的解释,这是有道理的。理解,我错误地认为是因为我们有一个超类的ItemBase,子类将在被反射时自动定义。对我来说有点疏忽。 – JadedEric 2011-04-20 10:05:00

1

你可以尝试这样的事:

 Type type = ret.GetType(); 
     Type listType = typeof(IEnumerable<T>); 
     if (type == listType || type.IsSubclassOf(listType)) 
     { 
      // 
     } 
1

首先,这是错误的:

Type classType = className.GetType(); 

此结构将产生类型className这是String但不是名称为stor的类型编辑于className

一个更好,更类型安全的方法是:

public IEnumerable<TItem> InvokeGenericMethod<TItem, TContainer>(...) 
    where TItem : ItemBase 
    where TContainer : class, new() 
{ 
    TContainer container = new TContainer(); 
    ... 
} 

更新:万一TContainer类型在哪里InvokeGenericMethod被称为地方静态已知,对一脸的中静态Type.GetType方法来解析其字符串名称的实际名称。在最简单的情况下,Type.GetType(String)方法访问您的类型的组件限定名称,例如, "MyNamespace.City, MyAssembly"

+0

您好Ondrej,您的提案将在实际类已知它是“纯粹”形式的情况下工作,但是,我有一个在我的控制下的下拉框,它将实体(类)的名称列为字符串值。我需要从程序集中获取关联字符串的基础类型。我会进一步调查,因为如果我改变自己的逻辑,我觉得你提出的解决方案可能有价值。 – JadedEric 2011-04-20 10:07:06

+0

@JadedEric Undestood并相应地更新了我的答案。但是,如果您可以将自己的逻辑转变为更安全的解决方案,可能会避免反思,您将来通常会从中受益。 – 2011-04-20 10:53:35