如何将对象转换为Type属性中定义的类型?

时间:2014-02-19 18:09:56

标签: c# generics reflection

我的课程看起来像这样:

public RepositoryManager
{
    public Type Context {get; private set;}

    public RepositoryManager(Type context)
    {
        Context = context;
    }

    public IRepository<T> GetRepository<T>() where T : class
    {
        // create an instance of Context to pass to repo ctor
        var contextInstance = Activator.CreateInstance(Context);  // fail
        return new Repository<T>(contextInstance);
    }
}

我知道我需要将contextInstance作为上下文的类型,但我不知道如何做到这一点。我无法做typeof(Context),因为编译器抱怨我使用了像'type'这样的属性(在这种情况下我的意图)。

如何将Context属性中存储的类型实例传递给Repository对象的构造函数?

更新/澄清

基于一些答案,我似乎没有清楚地解释自己。

我在Context属性中存储的类型很可能是DbContext的实现...例如由实体框架代码第一次逆向工程创建的SailingDbContext。它也可以是JudoDbContext。或者其他一些完全无关的背景。我不知道它可能是什么。但是,我知道该类型可用于程序集。

存储库中的T将会出现POCO。也许客户或产品。我真的不知道,我也不在乎......我只知道它会存在。

Repository的构造函数需要传递Context属性中定义的类型的实例。这是我的问题。如何将Activator创建的对象强制转换为Context属性中定义的类型?

根据请求,我添加了Repository类的构造函数。但是,我担心这会使事情进一步混乱。我没有看到如何尝试将Activator创建的对象转换为对象的实例,以及实例传递给它的内容会影响对象的实例。

public class Repository<T> : IRepository<T>, IDisposable where T : class
{

    private readonly DbSet<T> _dbSet;
    public DbContext Context {get; set;}

    public Repository() 
    {
        // dont use ...
    }

    public Repository(DbContext context)
    {
        Context = context;
        _dbSet = Context.Set<T>();
    }

    // lots more code snipped
 }

请记住,这是IRepository接口的具体实现。将Activator创建的对象直接转换为类型DbContext并不是一个好的答案。

同样,我只是想将一个对象强制转换为Context属性中定义的类型。

4 个答案:

答案 0 :(得分:3)

您需要使用“dynamic”而不是“var”来获得运行时动态创建的好处。 “var”解析/验证仍然在编译时发生。

dynamic contextInstance = Activator.CreateInstance(Context);

答案 1 :(得分:0)

您可以在MakeGenericType的帮助下动态创建泛型类型,然后简单地转换它:

public class RepositoryManager
{
    public Type Context { get; private set; }

    public RepositoryManager(Type context)
    {
        Context = context;
    }

    public IRepository<T> GetRepository<T>() where T : class
    {
        var contextInstance = Activator.CreateInstance(Context);
        var repositoryType = typeof(Repository<>).MakeGenericType(Context);
        var repository = Activator.CreateInstance(repositoryType, contextInstance);
        return (IRepository<T>)repository;
    }
}

答案 2 :(得分:0)

我建议你将UnitOfWork模式与Repository一起使用:

public class SqlRepository<T>: IRepository<T> where T: class, IEntity
{
    protected readonly DbSet<T> _objectSet;

    public SqlRepository(ApplicationDbContext context)
    {
        _objectSet = context.Set<T>();

    }
}

和你的UnitOfWork类:

public class SqlUnitOfWork<T> : IUnitOfWork<T> where T : class, IEntity
{
    private ApplicationDbContext _db;
    public SqlUnitOfWork(ApplicationDbContext context)
    {
        _db = context;
    }

    public IRepository<T> Repistory
    {
        get
        {
            return new SqlRepository<T>(_db);
        }
    }

}

在asp.net mvc中有时你需要在同一个控制器上使用其他类型的存储库来进行测试 假设您需要在PersonController中查询帐户,然后在此模式中您可以轻松地在unitOfWork中编写类似的内容:

    public IRepository<TEntity> GetTypeRepository<TEntity>() where TEntity : class, IEntity
    {
        return new SqlRepository<TEntity>(_db);
    }

这样,每次需要新的存储库时,您都不需要实例化新的上下文。 我顺利接口定义了。 希望能帮助到你。 :)

答案 3 :(得分:0)

你试试这个吗?

var contextInstance = Activator.CreateInstance("YourAssemblyFullName", Context.FullName);