开发者

Using Entity Framework with abstract classes

开发者 https://www.devze.com 2023-02-28 01:34 出处:网络
Have a very interesting situation and can\'t seem to find anything concrete on the webs surrounding reflection, inheritance and generics.

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-开发者_StackOverflow中文版class to an abstract entity called 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:

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:

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:

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:

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.

I'm completely stumped here.

Any ideas, recommendations would be greatly appreciated.

Thanks,

Eric


Is it possible that you are using Framework 3.5? Generic co- and contravariance was introduced in .net 4.0. Thus, the following is not possible in 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:

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>. But, obviously, cities.Add(new Person()); cannot work (since the "real" (= static) type of cities is List<City>). Thus, List<Item> can never be a supertype of 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).


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.

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. In the simplest case the Type.GetType(String) method access an assembly qualified name of your type, e.g. "MyNamespace.City, MyAssembly".

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号