2011-09-14 14 views
8

He estado tirando de mi cabello por un tiempo en este caso, esencialmente estoy tratando de implementar una fábrica de repositorios genéricos, que se llama de la siguiente manera:Genéricos y Reflexión - GenericArguments [0] viola la restricción del tipo

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

la fábrica repositorio tiene el siguiente aspecto:

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

Cuando trato de llamar a la GetRespository funcionan de la siguiente línea de falla

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

El error que consigo es:

ArgumentException - GenericArguments [0], 'Framework.Repositories.IRepository`1 [Apps.Documents.Entities.PerpetualDocument]', en 'Framework.Repositories.DocumentLibraryRepository`1 [T] 'viola la restricción de tipo' T '.

¿Alguna idea sobre qué está pasando mal aquí?

EDIT:

La implementación del repositorio es el siguiente:

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

    ... 
} 

Y el IRepository parece:

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

¿Echas en falta una declaración de devolución allí? ¿Pegaste una copia completa de ese método? –

+0

Además, ¿por qué estás buscando la presencia de un constructor sin parámetros cuando claramente intentas invocar un constructor con parámetros? Si tiene un constructor sin parámetros, es muy probable que sea el 0º constructor devuelto por 'GetConstructors', en cuyo caso se producirá un error al llamarlo * con * parámetros. –

+0

Sí lo siento 'return default (T)' debería estar al final. – Bevan

Respuesta

6

Su código intenta crear una instancia de DocumentLibraryRepository<IRepository<Document>> en lugar de DocumentLibraryRepository<Document>.

que desea utilizar este código en su lugar:

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

Lo siento, sí, debería haber agregado que: interfaz pública IRepository donde T: clase { void Añadir (entidad T); void Eliminar (entidad T); void Update (entidad T); T FindById (int entityId); IEnumerable Find (string camlQuery); IEnumerable Todo(); } – Bevan

+0

@Bevan: OK. Por favor mira mi respuesta actualizada. Esto debería solucionar tu problema. –

+0

Muchas gracias, ¡eso fue lo que hizo! Eres un salvavidas :) – Bevan

0

Esto sugeriría que tal vez usted ha utilizado una restricción where del tipo genérico DocumentLibraryRepository<T> y que el tipo PerpetualDocument no coincide con la restricción

0

Tal vez mi respuesta puede ayudar a alguien que tiene el mismo error. Mi escenario es:

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

Así que en tiempo de ejecución cuando se carga método Run() (no ejecutado) me sale una excepción: GenericArguments [0] .... System.EventHandler`1 [TEventArgs]' viola la restricción del parámetro de tipo 'TEventArgs' .. en el método Run().

No sé si es un error de .NET, pero en mi caso SOLUCIONÉ este problema cambiando el tipo de propiedad TypedEvent en una clase desde EventHandler<B> a EventHandler. Mi escenario se convierta en:

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

espero que pueda ayudar a alguien.

Cuestiones relacionadas