2011-09-14 110 views
8

我一直在這一拉我的頭髮一段時間,本質上我試圖實現一個通用的知識庫工廠,這是所謂的如下:泛型和反射 - GenericArguments [0]違反類型約束

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(); 
    } 
+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刪除(T實體); void Update(T entity); T FindById(int entityId); IEnumerable Find(string camlQuery); IEnumerable All(); } – Bevan

+0

@Bevan:好的。請看我更新的答案。這應該可以解決你的問題。 –

+0

非常感謝你,這個伎倆!你是一個拯救生命的人:) – Bevan

0

這表明,也許你已經使用了where約束的泛型類型DocumentLibraryRepository<T>和類型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]」不符合方法Run()上的類型參數'TEventArgs'..的約束。

我不知道它是否是一個.NET錯誤,但在我的情況下,我解決了這個問題,將TypedEvent屬性的類型從鍵入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"; 
    } 
} 

我希望可以幫助別人。

相關問題