V
V
Vadim Martynov2014-01-11 00:35:09
.NET
Vadim Martynov, 2014-01-11 00:35:09

Autodetection of Generic types within Generic (Get() where TEntity: IEntity)?

Hi people!
I always have problems with generic.
There is the following class structure:

class Entity<TId> where TId : struct 
{ 
    public virtual TId Id { get; set; } 
}

interface IRepository<T, in TId> where T : Entity<TId> where TId : struct 
{ 
    T Get(TId id); 
    IList<T> GetAll(); ... 
}

class RepositoryProvider
{
        public IRepository<TEntity, TId> GetRepository<TEntity, TId>() where TEntity : Entity<TId> where TId : struct
        { ... }
}

I don't like the need to specify both generic parameters when calling GetRepository. After all, when I substitute the first parameter, then from it you can extract information about the second. A class cannot inherit Entity twice with different TIds, so the information is unambiguous.
I want to be able to write:
provider.GetRepository<Department>();
instead of But when trying to declare a method like this:
provider.GetRepository<Department, int>();
public IRepository<TEntity, TId> GetRepository<TEntity>() where TEntity : Entity<TId> where TId : struct

the obvious compilation error "The type or namespace name 'TId' could not be found (are you missing a using directive or an assembly reference?)" occurs.
Is there a way to get around this limitation? I would arrange reflection or Emit, but I can’t imagine how to apply them here. I apologize for the rambling way of expressing my thoughts.

Answer the question

In order to leave comments, you need to log in

1 answer(s)
A
Anton, 2014-01-11
@Vadimyan

Might help:

RepositoryProvider provider = new RepositoryProvider();
dynamic repo = provider.GetRepository<Entity<int>>();
List<Entity<int>> list = repo.GetAll();
Entity<int> entry = repo.Get(10);

interface Entity { }

class Entity<TId> : Entity
    where TId : struct
{
    public virtual TId Id { get; set; }
}

interface IRepository<T, in TId>
    where T : Entity<TId>
    where TId : struct
{
    T Get(TId id);
    IList<T> GetAll();
}

class Repo<T, TId> : IRepository<T, TId>
    where T : Entity<TId>
    where TId : struct
{
    public T Get(TId id)
    {
        return default(T);
    }

    public IList<T> GetAll()
    {
        return new List<T>();
    }
}

class RepositoryProvider
{
    public dynamic GetRepository<TEntity>()
        where TEntity : Entity
    {
        Type genericParam = typeof(TEntity).GetGenericArguments()[0];
        return Activator.CreateInstance(typeof(Repo<,>).MakeGenericType(typeof(TEntity), genericParam));
    }
}

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question