Generics & Reflection - GenericArguments [0] нарушает ограничение типа - PullRequest
11 голосов
/ 14 сентября 2011

Я потянул свои волосы на некоторое время на этом, по сути, я пытаюсь реализовать универсальную фабрику репозитория, которая называется следующим образом:

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

Фабрика репозитория выглядит какследующее:

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

Когда я пытаюсь вызвать функцию GetRespository, происходит сбой следующей строки

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

Я получаю ошибку:

ArgumentException - GenericArguments[0], «Framework.Repositories.IRepository`1 [Apps.Documents.Entities.PerpetualDocument]» в «Framework.Repositories.DocumentLibraryRepository`1 [T]» нарушает ограничение типа «T».

Есть идеи о том, что здесь происходит не так?

РЕДАКТИРОВАТЬ:

Реализация хранилища выглядит следующим образом:

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

   ...
}

И IRepository выглядит следующим образом:

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

Ответы [ 4 ]

8 голосов
/ 14 сентября 2011

Ваш код пытается создать экземпляр DocumentLibraryRepository<IRepository<Document>> вместо DocumentLibraryRepository<Document>.

Вы хотите использовать этот код вместо:

var genericArgument = typeof(T).GetGenericArguments().FirstOrDefault();
if (tempType != null && genericArgument != null)
{
    Type newType = tempType.MakeGenericType(genericArgument);
1 голос
/ 11 мая 2019

У меня была точно такая же ошибка, но проблема и решение были другими. У меня было 4 класса Model, 1 базовый класс, и только 3 из них унаследованы от базового, 4-й - нет. Как только последний класс унаследовал базовый класс, ошибка исчезла.

1 голос
/ 14 сентября 2011

Это может означать, что, возможно, вы использовали ограничение where для универсального типа DocumentLibraryRepository<T> и что тип PerpetualDocument не соответствует этому ограничению

0 голосов
/ 29 мая 2017

Возможно, мой ответ может помочь кому-то, у кого такая же ошибка. Мой сценарий:

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

Таким образом, во время выполнения, когда метод Run () загружен (не выполнен), я получаю исключение:

GenericArguments [0] .... System.EventHandler`1 [TEventArgs] 'Нарушает ограничение параметра типа 'TEventArgs' .. на метод Run ().

Я не знаю, является ли это ошибкой .NET, но в моем случае я решил эту проблему, изменив тип свойства TypedEvent в классе A с набранного EventHandler<B> на EventHandler. Мой сценарий стал:

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

Надеюсь, это кому-нибудь поможет.

...