如何投射到MyInterface <tentity> </tentity>

时间:2012-07-31 11:02:49

标签: c# generics casting

我已经实现了一个通用存储库,但是要求在运行时动态创建适当的存储库,并将实体类型作为字符串。

我已设法使用以下方法创建存储库:

        Assembly common = Assembly.LoadFrom(@"CommonLibrary.dll");
        Type entityType = common.GetType("Models.OneOfManyEntities");
        Type repoType = typeof(TradeSiftRepository<>).MakeGenericType(entityType);

        var repo = Activator.CreateInstance(repoType, new UnitOfWork());

但是repo是一个对象,我真的希望它转换为IRepository<TEntity>我尝试了IRepository<entityType>但是这不正确

这是repo的界面:

public interface IRepository<TEntity> : IDisposable where TEntity : class
{
    IQueryable<TEntity> FindAll();
    IQueryable<TEntity> Find(Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, string includeProperties = "");
    TEntity FindById(object Id);
    void Insert(TEntity entity);
    void Update(TEntity entity);
    void Delete(object id);
    void Delete(TEntity entity);
}

repo的激活实例类型正确,但Activator返回一个对象类型,所以我需要将其强制转换为使用方法。

2 个答案:

答案 0 :(得分:1)

您说要将对象强制转换为IRepository<TEntity>,但TEntity仅在运行时可用(您在Type变量中引用了entityType对象)。

如果可能IRepository<entityType>,您希望从FindById等方法中获得什么?我认为可能是一个entityType个实例?现在,由于entityType可以是任何类型,并且仅在运行时确定,编译器可能不知道如何编译涉及entityType变量的任何代码。因此,IRepository<entityType>是不可能的。

有两种可能的解决方案,具体取决于您希望实现的目标:

  1. 如果您不想运行任何需要了解实体对象的代码,请实现一个额外的IRepository - 类似于处理object类型实体的接口(并且可能会抛出ArgumentException如果添加的任何内容与当前entityType不匹配,则返回s。将Activator.CreateInstance调用的结果转换为新的接口类型。
  2. 创建一个新的泛型类,将实体类型作为泛型参数。将处理您的实体和存储库的所有代码移动到该新类中,它始终使用作为泛型参数提供的实体类型。通过Activator.CreateInstance实例化该通用类,与您现在使用TradeSiftRepository<T>类直接实现的类似。

答案 1 :(得分:0)

我不认为你问的是可能的。如果您的代码正在接收表示泛型类型参数的字符串,则它所代表的类型只能在运行时确定。但是,应在编译时指定泛型类型参数。

如果您想将它作为返回类型的类型参数使用,我认为您必须接收实体类型作为泛型类型参数:

public IRepository<TEntity> MakeRepository<TEntity>() where TEntity : class
{
    var repo = new TradeSiftRepository<TEntity>(new UnitOfWork());
    return repo;
}

IRepository<User> userRepository = MakeRepository<User>();

如果你肯定想要将实体类型名称作为字符串接收,那么在编译时将结果转换为实际类型的责任应该通过调用代码来完成,因为调用代码是指定类型的:

public object MakeRepository(string entityTypeName)
{
    Assembly common = Assembly.LoadFrom(@"CommonLibrary.dll");
    Type entityType = common.GetType(entityTypeName);
    Type repoType = typeof(TradeSiftRepository<>).MakeGenericType(entityType);

    var repo = Activator.CreateInstance(repoType, new UnitOfWork());
    return repo;
}

IRepository<User> userRepository = (IRepository<User>)MakeRepository("User");

但是,通过使用该方法的通用版本可以简化上述代码;重复较少。如果调用代码也不知道它要求的类型,我认为你没有选择。

一种可能的解决方法是返回动态类型,这将使​​调用代码假定它具有其作者想要的类型的对象:

public dynamic MakeRepository(string entityTypeName)
{
    Assembly common = Assembly.LoadFrom(@"CommonLibrary.dll");
    Type entityType = common.GetType(entityTypeName);
    Type repoType = typeof(TradeSiftRepository<>).MakeGenericType(entityType);

    var repo = Activator.CreateInstance(repoType, new UnitOfWork());
    return repo;
}

dynamic userRepository = MakeRepository("ConsoleApplication1.User");
User user = userRepository.FindById(1);