Sailing Judo
Sailing Judo

Reputation: 11243

How can I cast an object as a type defined in a Type property?

I have class that looks something like this:

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);
    }
}

I know I need to cast contextInstance as the type of Context but I'm not sure how to do this. I can't do typeof(Context) because the compiler complains I am using a property like a 'type' (which is my intent in this case).

How can I pass an instance of the type stored in the Context property to the constructor of the Repository object?

Update/Clarifications

Based on some of the answers it appears I did not explain myself clearly.

The type I am storing in the Context property is most likely going to be an implementation of DbContext... for example SailingDbContext created by Entity Framework code first reverse engineering. It can also be JudoDbContext. Or some other completely unrelated context. I have no idea what it might be. However, I do know that that type will be available to the assembly.

The T in Repository will be come kind of POCO. Perhaps Customer, or Products. I don't really know and I don't care... I just know it will exist.

The constructor for Repository needs to be passed an instance of the type defined in the Context property. This is the point of my question. How can I cast the object created by Activator to the type defined in the Context property?

Per request, I am adding the constructor for Repository class. However, I fear this will confuse things further. I don't see how attempting to cast an instance of object an object created by Activator to a type defined in a property can be influenced by what the instance is getting passed to.

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
 }

Keep in mind that this is a concrete implementation of the IRepository interface. Casting the object created by Activator directly to a type DbContext is not a good answer.

Again, I'm just trying to cast an object to a type defined in the Context property.

Upvotes: 1

Views: 492

Answers (4)

thorphin
thorphin

Reputation: 118

You need to use "dynamic" instead of "var" to get the benefits of dynamic creation at run-time. "var" resolution/validation still occurs at compile time.

dynamic contextInstance = Activator.CreateInstance(Context);

Upvotes: 3

TeeBo
TeeBo

Reputation: 1

Have you try this?

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

Upvotes: 0

SHM
SHM

Reputation: 1952

i suggest you use UnitOfWork pattern with Repository:

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

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

    }
}

and you UnitOfWork class:

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);
        }
    }

}

in asp.net mvc some times you need other type repository on same controller for examle lets say you need to query accounts in PersonController then in this pattern you easily can write something like this in you unitOfWork:

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

this way you dont need to instatiate a new context every time you need new repository. i skiped interface definitions btw. hope it helps. :)

Upvotes: 0

Konrad Kokosa
Konrad Kokosa

Reputation: 16878

You can create generic type dynamically with help of MakeGenericType and then cast it simply:

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;
    }
}

Upvotes: 0

Related Questions