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

5

14

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();
    }
Haloid answered 14/9, 2011 at 10:30 Comment(4)
Are you missing a return statement there? Did you paste a complete copy of that method?Korwin
Also, why are you checking for the presence of a parameterless constructor when clearly you intend to invoke a constructor with parameters? If you have a parameterless constructor, it's most likely going to be the 0th constructor returned by GetConstructors, in which case calling it with parameters will fail.Korwin
Yes sorry 'return default(T)' should be at the end.Haloid
In regards to the check for the parameterless constructor? What you are saying is correct, I was just playing around to see if I was doing something wrong tbh.Haloid
S
10

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);
Shermy answered 14/9, 2011 at 10:39 Comment(2)
Sorry yes I should have added that: 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(); }Haloid
@Bevan: OK. Please see my updated answer. This should fix your problem.Shermy
F
3

I had this exactly same error, but the problem and solution was different. I had 4 Model classes, 1 base class, and only 3 of them inherited from the base, 4th did not. Once the last class inherited the base class, the error disappeared.

Felike answered 11/5, 2019 at 8:54 Comment(1)
I've done this twice today, and had to google for your answer both times. ::sigh:: It's gonna be a long day. Either way, this answer is brilliant!Aeriela
V
1

This would suggest that perhaps you've used a where constraint on the generic type DocumentLibraryRepository<T> and that the type PerpetualDocument does not match that constraint

Vain answered 14/9, 2011 at 10:41 Comment(0)
G
0

Maybe my answer can help someone that have the same error. My scenario is :

public class B
{
    public string Name;
}

public class A
{
    public EventHandler<B> TypedEvent;

    public void MyMethod(B item)
    {
        if (TypedEvent != null)
        {
            TypedEvent(null, item);
        }
    }
}

public class T
{
    public void Run()
    {
        A item = new A();
        item.TypedEvent += new EventHandler<B>(ItemEvent);
    }

    private void ItemEvent(object sender, B b)
    {
        b.Name = "Loaded";
    }
}

So at runtime when Run() method is loaded (not executed) I get an exception:

GenericArguments[0] .... System.EventHandler`1[TEventArgs]' Violates the constraint of the type parameter 'TEventArgs' .. on method Run().

I don't know if it's a .NET bug, but in my case i SOLVED this problem changing the type of TypedEvent property in A class from typed EventHandler<B> to EventHandler. My scenario become:

public class B
{
    public string Name;
}

public class A
{
    public EventHandler TypedEvent;

    public void MyMethod(B item)
    {
        if (TypedEvent != null)
        {
            TypedEvent(item, null);
        }
    }
}

public class T
{
    public void Run()
    {
        A item = new A();
        item.TypedEvent += new EventHandler(ItemEvent);
    }

    private void ItemEvent(object sender, EventArgs e)
    {
        B b = sender as B;
        b.Name = "Loaded";
    }
}

I hope that can help someone.

Gallard answered 29/5, 2017 at 13:59 Comment(0)
R
0

I had this problem when I have changed my generic type to abstract at the suggestion of Resharper, obviously it couldn't be instantiated and resulted in this error.

Removed abstract and the method.MakeGenericMethod(type) line works again.

Rochet answered 24/9, 2021 at 10:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.