2011-09-14 3 views
8

유형의 제약 조건을 위반합니다. 본질적으로 다음과 같이 호출되는 제네릭 저장소 팩토리를 구현하려고합니다. 잠시 동안 제 머리칼을 꺼내 왔습니다.Generics & Reflection - GenericArguments [0]이

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)); 
,536 실패 기능 :
var resposFactory = new RepositoryFactory<IRepository<Document>>(); 

저장소 공장은 다음과 같습니다

내가 오류는 다음과 같습니다

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

거기에 신고서가 누락 되었습니까? 그 방법의 완전한 사본을 붙여 넣었습니까? –

+0

또한 매개 변수가있는 생성자를 명확하게 호출 할 때 매개 변수없는 생성자가 있는지 확인하는 이유는 무엇입니까? 매개 변수없는 생성자를 사용하면 'GetConstructors'에 의해 반환 된 0 번째 생성자가 될 가능성이 높습니다.이 경우 * 매개 변수를 * 매개 변수로 호출하면 실패합니다. –

+0

예 죄송합니다 '반환 기본값 (T)'이 끝에 와야합니다. – Bevan

답변

6

귀하의 코드 대신 DocumentLibraryRepository<IRepository<Document>>의 인스턴스를 만들려고 DocumentLibraryRepository<Document>.

는 대신이 코드를 사용하려면 :

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

죄송합니다. 추가해야합니다 : public interface IRepository T : class { void Add (T entity); void Remove (T 엔티티)를 제거합니다. void 업데이트 (T 엔티티); T FindById (int entityId); IEnumerable 찾기 (문자열 camlQuery); IEnumerable 모두(); } – Bevan

+0

@ 베반 : 확인. 내 업데이트 된 답변을 참조하십시오. 이렇게하면 문제가 해결됩니다. –

+0

대단히 고마워, 그 트릭을! 당신은 생명의 은인 :) – Bevan

0

이 아마도 당신이 제네릭 형식 DocumentLibraryRepository<T>where 제약 조건을 사용했다고 및 유형 PerpetualDocument가 제약

0

에게 일치하지 않음을 제안 어쩌면 내 대답이 같은 오류가있는 사람을 도울 수 있습니다. 내 시나리오는 다음과 같습니다

실행() 메소드가 나는 예외 얻을 (실행되지 않음)로드 런타임에 따라서
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"; 
    } 
} 

: GenericArguments [0] ... System.EventHandler`1가 [TEventArgs] '에 위배된다을 메서드 매개 변수 'TEventArgs'의 제약 조건. Run() 메서드.

.NET 버그인지는 모르지만 제 경우에는 A 클래스의 TypedEvent 속성 유형을 EventHandler에 EventHandler<B>에서 변경하는 문제를 해결했습니다. 내 시나리오 :

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

나는 누군가를 도울 수 있기를 바랍니다.