Как преобразовать <T>в его базовый тип для универсального метода? - PullRequest
1 голос
/ 30 августа 2010

У меня есть общий класс CRUD для выполнения добавления, удаления, выбора, создания объектов моей сущности.

один из них - Сообщение имеет два производных класса - order_message и report_message.

Моя проблема в том, что в моем универсальном классе мне нужен набор объектов для выполнения операций типа crud, но набор объектов не принимает тип производного класса, он принимает только тип базового класса.

Это ошибка, которую я получил:

Для указанного типа сущности 'CustomerWebPortal_Entities.Order_Message' не определены EntitySet. Если 'CustomerWebPortal_Entities.Order_Message' является производным типом, используйте вместо него базовый тип.

Я пытался использовать typeof (T) .BaseType для замены T, и причина не работала.

Как мне исправить это?

Это общий обзор класса:

 public abstract class baseCrudDao<T> : ICrudDao<T> where T : class
{
    private System.Data.Objects.ObjectContext _context;

    private System.Data.Objects.ObjectSet<T> _entity; 
    public baseCrudDao()
    {

        _context = new CustomerWebPortalEntities();
        _entity = _context.CreateObjectSet<T>(); <-- error at here, only accept base type

    }

Ответы [ 2 ]

3 голосов
/ 31 августа 2010

Что ж, у меня наконец-то появилась возможность написать прототип, как было предложено. Я думаю, что что-то подобное будет работать, но я не проверял это. Теперь все ваши грубые методы могут быть определены для члена IObjectSet<>.

public class Crud<EntityType> where EntityType : class
{
    private readonly ObjectContext Context;
    private readonly IObjectSet<EntityType> Entities;

    public Crud(ObjectContext context)
    {
        Context = context;

        Type BaseType = GetBaseEntityType();

        if (BaseType == typeof(EntityType))
        {
            Entities = Context.CreateObjectSet<EntityType>();
        }
        else
        {
            Entities = (IObjectSet<EntityType>)Activator.CreateInstance(typeof(ObjectSetProxy<,>).MakeGenericType(typeof(EntityType), BaseType), Context);
        }
    }

    private static Type GetBaseEntityType()
    {
        //naive implementation that assumes the first class in the hierarchy derived from object is the "base" type used by EF
        Type t = typeof(EntityType);

        while (t.BaseType != typeof(Object))
        {
            t = t.BaseType;
        }

        return t;
    }
}

internal class ObjectSetProxy<EntityType, BaseEntityType> : IObjectSet<EntityType>
    where EntityType : BaseEntityType
    where BaseEntityType : class
{
    private readonly IObjectSet<BaseEntityType> Entities;

    public ObjectSetProxy(ObjectContext context)
    {
        Entities = context.CreateObjectSet<BaseEntityType>();
    }

    public void AddObject(EntityType entity)
    {
        Entities.AddObject(entity);
    }

    //TODO: implement remaining proxy methods

    public IEnumerator<EntityType> GetEnumerator()
    {
        return Entities.OfType<EntityType>().GetEnumerator();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    public Type ElementType
    {
        get { return typeof(EntityType); }
    }

    public Expression Expression
    {
        get { return Entities.OfType<EntityType>().Expression; }
    }

    public IQueryProvider Provider
    {
        get { return Entities.Provider; }
    }
}
0 голосов
/ 30 августа 2010

Одним из обходных путей будет использование двух параметров универсального типа (для базового класса), таких как

public abstract class baseCrudDao<T, U> : ICrudDao<T> where U : class, T: U
{
    ...
    public baseCrudDao()
    {
        _context = new CustomerWebPortalEntities();
        _entity = _context.CreateObjectSet<U>(); <-- error at here, only accept base type
    }
    ...
}

Использовать Message вместо U. Если у вас много типов, и не у всех есть отношения наследования, тогдаограничение T: U не сработает, и вам, возможно, нужно использовать ограничение T: class.Я также предлагаю создать еще один базовый класс скелета, который будет использоваться для других типов, таких как

public abstract class base2CrudDao<T> : baseCrudDao<T, T>

, чтобы вам не приходилось указывать параметр U для классов, которые не имеют отношения наследования.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...