2011-09-14 20 views
8

türünün kısıtlamasını ihlal ediyor, bu yüzden bir süre saçımı dışarı çekiyorum, aslında şu şekilde çağrılan genel bir depo fabrikası uygulamaya çalışıyorum: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 }); 
     } 
    } 
} 

Ben GetRespository aramaya çalıştığımda

aşağıdaki satırı

Type newType = tempType.MakeGenericType(typeof(T)); 
başarısız işlev:
var resposFactory = new RepositoryFactory<IRepository<Document>>(); 

depo fabrika aşağıdaki gibi görünür

I elde hatadır:

ArgumentException - GenericArguments [0] 'Framework.Repositories.IRepository`1 [Apps.Documents.Entities.PerpetualDocument]', Framework.Repositories.DocumentLibraryRepository`1' ile [T] 'T' türünün kısıtlamasını ihlal ediyor.

Burada yanlış olanlarla ilgili herhangi bir fikir var mı?

DÜZENLEME: Aşağıdaki

depo uygulanması gibi:

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

    ... 
} 

Ve benzeri IRepository görünür:

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

Orada bir iade bildirimi eksik misiniz? Bu yöntemin tam bir kopyasını mı yapıştırdınız? –

+0

Ayrıca, bir kurucu parametrelerini açıkça çağırmak istediğinizde neden parametresiz bir kurucunun varlığını kontrol ediyorsunuz? Eğer parametresiz bir kurucunuz varsa, büyük olasılıkla 'GetConstructors' tarafından döndürülen 0 kurucu olacaktır, bu durumda * ile * parametreleri başarısız olacaktır. –

+0

Evet özür dileriz 'dönüş varsayılanı (T)' en sonunda olmalıdır. – Bevan

cevap

6

Kodunuz yerine DocumentLibraryRepository<IRepository<Document>> bir örneğini oluşturmaya çalışır DocumentLibraryRepository<Document>.

Bunun yerine bu kodu kullanmak istiyorum:

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

Üzgünüm evet ekledim: kamu arabirimi İkincil Deposu Burada T: sınıf { void Ekleme (T öğesi); void Remove (T varlığı); void Güncelleme (T varlık); T FindById (int entityId); IEnumerable Bul (string camlQuery); IEnumerable Tümü(); } – Bevan

+0

@Bevan: Tamam. Lütfen güncellenmiş yanıtıma bakın. Bu senin problemini çözmeli. –

+0

Çok teşekkür ederim, bu hile yaptı! Sen bir hayat kurtarıcısın :) – Bevan

0

Bu belki de genel türü DocumentLibraryRepository<T> üzerinde where kısıtlamayı kullandım o ve tip PerpetualDocument o kısıt

0

uymuyor öneririm Belki de cevabım aynı hataya sahip birine yardımcı olabilir. Benim senaryo:

Çalıştır() yöntemi bir istisna olsun (yürütülmez) yüklenir zamanında Yani
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]' ihlal ediyor 'TEventArgs' tür parametresinin kısıtlaması .. yöntemi Run().

Bu bir .NET hatası olup olmadığını bilmiyorum, ancak durumumda Bu sorun, A sınıfındaki TypedEvent özelliği türünü EventHandler<B>'dan EventHandler'e değiştirerek SOLVED. Benim senaryo haline:

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

O biri yardımcı olabilir umuyoruz.