简体   繁体   English

将实体框架与抽象类一起使用

[英]Using Entity Framework with abstract classes

Have a very interesting situation and can't seem to find anything concrete on the webs surrounding reflection, inheritance and generics. 有一个非常有趣的情况,似乎无法在网络上找到任何有关反射,继承和泛型的具体内容。

To start off with: 首先开始:

I have a base abstract classed, called: 我有一个基本的抽象分类,名为:

public abstract class ItemBase
{
     // default properties
}

ItemBase then becomes my super-class to an abstract entity called Item: 然后,ItemBase成为我的超抽象类,称为Item:

public abstract class Item
{
    // some extra properties
}

The idea behind this is to construct entities that will inherit from Item with additional properties set: 其背后的想法是构造将从Item继承并设置其他属性的实体:

public partial class City : Item {}

Now, in a test method I'm trying to use reflection to invoke a method on the passed entity and return whatever data, in what ever form, back from the method. 现在,在测试方法中,我试图使用反射在传递的实体上调用方法,并从该方法返回以任何形式返回的任何数据。

Assuming, for testing purposes we have a method in State, that returns a collection of all major cities: 假设出于测试目的,我们在State中有一个方法,该方法返回所有主要城市的集合:

public List<City> GetAllMajorCities() {}

In my stubs I might have a test to get all cities: 在我的存根中,我可能会进行一次测试以获取所有城市:

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

Then the InvokeGenericMethod(string, string, object[] args) looks something like: 然后,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);
}

In theory, from the example given, the value of "ret" should be a type of IEnumerable, however, the returning type, if added to a watch to investivage, return List, if I check the ret value as: 从理论上讲,从给出的示例中,“ ret”的值应该是IEnumerable的类型,但是,如果我将ret值检查为:,则返回类型(如果添加到要监视的手表中)将返回List。

if (ret is IEnumerable<T>)

it ignores the check. 它忽略了检查。

If I change 如果我改变

public List<City> GetAllMajorCities() {}

to

public List<ItemBase> GetAllMajorCities() {}

It seems to adhere to the inheritance and allow me to cast it to IEnumberable. 它似乎坚持继承并允许我将其强制转换为IEnumberable。

I'm completely stumped here. 我完全被困在这里。

Any ideas, recommendations would be greatly appreciated. 任何想法,建议将不胜感激。

Thanks, 谢谢,

Eric 埃里克

Is it possible that you are using Framework 3.5? 您是否正在使用Framework 3.5? Generic co- and contravariance was introduced in .net 4.0. .net 4.0中引入了通用协和逆。 Thus, the following is not possible in Framework 3.5: 因此,在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>.
    }
}

Note that the following (which is what you are trying to achieve) won't even work in .net 4.0: 请注意,以下(这是您要实现的目标)甚至无法在.net 4.0中使用:

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

Why doesn't that work? 为什么不起作用? Because it must be possible to add arbitrary Item s to a List<Item> . 因为必须可以将任意Item添加到List<Item> But, obviously, cities.Add(new Person()); 但是,很显然, cities.Add(new Person()); cannot work (since the "real" (= static) type of cities is List<City> ). 无法工作(因为“真实”(=静态)类型的citiesList<City> )。 Thus, List<Item> can never be a supertype of List<City> . 因此, List<Item>永远不能是List<City>的超类型。

You cannot add items to an IEnumerable, which is why there is a subtype relationship between IEnumerable<City> and IEnumerable<Item> (but only in .net 4.0, as mentioned above). 你无法将项目添加到一个IEnumerable,这就是为什么有之间的关系亚型IEnumerable<City>IEnumerable<Item> (但只能在.NET 4.0中,如上面提到的)。

You could try something like this: 您可以尝试这样的事情:

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

First of all, this is wrong: 首先,这是错误的:

Type classType = className.GetType();

This construct will yield the type of className which is String but not the type whose name is stored in className . 该构造将产生className类型,该类型为String但其名称类型存储在className

A better, more type-safe way would be: 更好,更类型安全的方式是:

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

Update: In case the TContainer type is not known statically at the place where InvokeGenericMethod is called, have a look on of the the static Type.GetType methods to resolve the actual name from its string name. 更新:万一TContainer类型在那里的地方静态已知InvokeGenericMethod被调用时,对的静态一看Type.GetType方法来解决其字符串名称的实际名称。 In the simplest case the Type.GetType(String) method access an assembly qualified name of your type, eg "MyNamespace.City, MyAssembly" . 在最简单的情况下, Type.GetType(String)方法访问您类型的程序集限定名称,例如"MyNamespace.City, MyAssembly"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM