使用实体框架和抽象类
本文关键字:抽象类 框架 实体 | 更新日期: 2023-09-27 17:50:33
有一个非常有趣的情况,似乎在网上找不到任何关于反射,继承和泛型的具体内容。
开头:
我有一个基本抽象类,叫做:
public abstract class ItemBase
{
// default properties
}
ItemBase然后成为一个名为Item的抽象实体的超类:
public abstract class Item
{
// some extra properties
}
这背后的思想是构造将继承Item的实体,并设置额外的属性:
public partial class City : Item {}
现在,在测试方法中,我试图使用反射来调用传递的实体上的方法,并返回任何数据,以任何形式,从方法返回。
假设,出于测试目的,我们在State中有一个方法,它返回所有主要城市的集合:
public List<City> GetAllMajorCities() {}
在我的存根中,我可能有一个测试来获得所有城市:
List<Item> cities = this.InvokeGenericMethod<Item>("State", "GetAllMajorCities", args);
然后InvokeGenericMethod(string, string, object[] args)看起来像:
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类型,然而,返回类型,如果添加到监视来调查,返回List,如果我检查ret值为:
if (ret is IEnumerable<T>)
忽略检查
如果我改变
public List<City> GetAllMajorCities() {}
public List<ItemBase> GetAllMajorCities() {}
它似乎坚持继承,并允许我将其强制转换为IEnumberable。
我完全被难住了。
如有任何意见、建议,不胜感激。
谢谢,埃里克
是否有可能使用框架3.5?泛型协逆变是在。net 4.0中引入的。因此,以下内容在框架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>();
为什么不行?因为一定有可能将任意的Item
s加到List<Item>
中。但是,显然,cities.Add(new Person());
不能工作(因为cities
的"真实"(=静态)类型是List<City>
)。因此,List<Item>
永远不能是List<City>
的超类型。
不能向IEnumerable中添加项,这就是为什么在IEnumerable<City>
和IEnumerable<Item>
之间存在子类型关系(但仅在。net 4.0中,如上所述)。
你可以尝试这样做:
Type type = ret.GetType();
Type listType = typeof(IEnumerable<T>);
if (type == listType || type.IsSubclassOf(listType))
{
//
}
首先,这是错误的:
Type classType = className.GetType();
这个构造将产生className
的类型,即String
,而不是名称存储在className
中的类型。
一个更好的、更类型安全的方法是:
public IEnumerable<TItem> InvokeGenericMethod<TItem, TContainer>(...)
where TItem : ItemBase
where TContainer : class, new()
{
TContainer container = new TContainer();
...
}
Update:如果TContainer
类型在调用InvokeGenericMethod
的地方不静态,请查看static Type.GetType
方法,以从其字符串名称解析实际名称。在最简单的情况下,Type.GetType(String)
方法访问您的类型的程序集限定名,例如"MyNamespace.City, MyAssembly"
。