Generics & Reflection - GenericArguments[0] violates the constraint of type

Bevan picture Bevan · Sep 14, 2011 · Viewed 16.7k times · Source

I've been pulling my hair out for awhile on this one, essentially I'm trying to implement a generic repository factory, which is called as follows:

var resposFactory = new RepositoryFactory<IRepository<Document>>();

The repository factory looks like the following:

public class RepositoryFactory<T> : IRepositoryFactory<T>
{
    public T GetRepository(Guid listGuid,
        IEnumerable<FieldToEntityPropertyMapper> fieldMappings)
    {
        Assembly callingAssembly = Assembly.GetExecutingAssembly();

        Type[] typesInThisAssembly = callingAssembly.GetTypes();

        Type genericBase = typeof (T).GetGenericTypeDefinition();

        Type tempType = (
            from type in typesInThisAssembly
            from intface in type.GetInterfaces()
            where intface.IsGenericType
            where intface.GetGenericTypeDefinition() == genericBase 
            where type.GetConstructor(Type.EmptyTypes) != null
            select type)
            .FirstOrDefault();

        if (tempType != null)
        {
            Type newType = tempType.MakeGenericType(typeof(T));

            ConstructorInfo[] c = newType.GetConstructors();

            return (T)c[0].Invoke(new object[] { listGuid, fieldMappings });
        }
    }
}

When I try to call the GetRespository function the following line fails

Type newType = tempType.MakeGenericType(typeof(T));

The error I get is :

ArgumentException - GenericArguments[0], 'Framework.Repositories.IRepository`1[Apps.Documents.Entities.PerpetualDocument]', on 'Framework.Repositories.DocumentLibraryRepository`1[T]' violates the constraint of type 'T'.

Any ideas on what's going wrong here?

EDIT:

The implementation of the repository is as follows:

public class DocumentLibraryRepository<T> : IRepository<T>
                                                where T : class, new()
{
   public DocumentLibraryRepository(Guid listGuid, IEnumerable<IFieldToEntityPropertyMapper> fieldMappings)
   {
        ...
   }

   ...
}

And the IRepository looks like:

public interface IRepository<T> where T : class
    {
        void Add(T entity);
        void Remove(T entity);
        void Update(T entity);
        T FindById(int entityId);
        IEnumerable<T> Find(string camlQuery);
        IEnumerable<T> All();
    }

Answer

Daniel Hilgarth picture Daniel Hilgarth · Sep 14, 2011

Your code tries to create an instance of DocumentLibraryRepository<IRepository<Document>> instead of DocumentLibraryRepository<Document>.

You want to use this code instead:

var genericArgument = typeof(T).GetGenericArguments().FirstOrDefault();
if (tempType != null && genericArgument != null)
{
    Type newType = tempType.MakeGenericType(genericArgument);