Использование Entity Framework с абстрактными классами - PullRequest
0 голосов
/ 20 апреля 2011

У вас очень интересная ситуация, и вы не можете найти что-то конкретное на паутине, окружающее отражение, наследование и дженерики.

Для начала:

У меня есть базовый абстрактный класс, называемый:

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 (строка, строка, объект [] 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 ]

3 голосов
/ 20 апреля 2011

Возможно ли, что вы используете 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>();

Почему это не работает? Потому что должно быть возможно добавить произвольные Item s к List<Item>. Но, очевидно, cities.Add(new Person()); не может работать (поскольку «реальный» (= статический) тип cities равен List<City>). Таким образом, List<Item> никогда не может быть супертипом List<City>.

Вы не можете добавлять элементы в IEnumerable, поэтому является отношением подтипа между IEnumerable<City> и IEnumerable<Item> (но только в .net 4.0, как упомянуто выше).

1 голос
/ 20 апреля 2011

Прежде всего, это неправильно:

Type classType = className.GetType();

Эта конструкция даст тип className, равный String, но не тип, имя которого хранится в className.

Лучшим, более безопасным для типов способом будет:

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

Обновление: В случае, если тип TContainer статически неизвестен в месте, где InvokeGenericMethodвызывается, посмотрите методы static Type.GetType, чтобы определить фактическое имя из его строкового имени.В простейшем случае метод Type.GetType(String) обеспечивает доступ к имени вашего типа с указанием сборки, например, "MyNamespace.City, MyAssembly".

1 голос
/ 20 апреля 2011

Вы можете попробовать что-то вроде этого:

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