1

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

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

        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>但这是不正确的

这是回购的界面:

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 返回一个对象类型,因此我需要对其进行强制转换以使用这些方法。

4

2 回答 2

1

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

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

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

  1. 如果您不想运行任何需要了解您的实体对象的代码,请实现一个额外IRepository的类似接口来处理类型的实体(如果添加的任何内容与当前的 s 不匹配,则object可能会抛出s )。将调用结果转换为该新接口类型。ArgumentExceptionentityTypeActivator.CreateInstance
  2. 创建一个将实体类型作为泛型参数的新泛型类。将处理您的实体和存储库的所有代码移动到该新类中,它始终使用作为通用参数提供的实体类型。Activator.CreateInstance通过类似于您现在直接对类执行的操作来实例化该泛型TradeSiftRepository<T>类。
于 2012-07-31T11:17:11.053 回答
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);
于 2012-07-31T11:48:18.577 回答