2016-01-04 5 views
5

Ben yönteme geçirilen enum bağlı bir depo oluşturan bir fabrika ile çalışıyorum (ne olduğunu düşünüyorum) çalışıyorum. Bu gibi görünüyor:Activator.CreateInstance

RepositoryFactory

public class RepositoryFactory 
{ 
    public IRepository<IEntity> GetRepository(FormTypes formType) 
    { 
     // Represents the IRepository that should be created, based on the form type passed 
     var typeToCreate = formType.GetAttribute<EnumTypeAttribute>().Type; 

     // return an instance of the form type repository 
     IRepository<IEntity> type = Activator.CreateInstance(typeToCreate) as IRepository<IEntity>; 

     if (type != null) 
      return type; 

     throw new ArgumentException(string.Format("No repository found for {0}", nameof(formType))); 
    } 
} 

IRepository

public interface IRepository <T> 
    where T : class, IEntity 
{ 
    bool Create(IEnumerable<T> entities); 

    IEnumerable<T> Read(); 

    bool Update(IEnumerable<T> entities); 

    bool Delete(IEnumerable<T> entities); 
} 

FormTypes

public enum FormTypes 
{ 
    [EnumType(typeof(Form64_9C2Repository))] 
    Form64_9C2, 

    [EnumType(typeof(Form64_9BaseRepository))] 
    Form64_9Base 
} 

EnumExtensions

public static class EnumExtensions 
{ 

    /// <summary> 
    /// Get the Enum attribute 
    /// </summary> 
    /// <typeparam name="T">The attribute</typeparam> 
    /// <param name="enumValue">The enum</param> 
    /// <returns>The type to create</returns> 
    public static T GetAttribute<T>(this System.Enum enumValue) 
     where T : Attribute 
    { 
     FieldInfo field = enumValue.GetType().GetField(enumValue.ToString()); 
     object[] attribs = field.GetCustomAttributes(typeof(T), false); 
     T result = default(T); 

     if (attribs.Length > 0) 
     { 
      result = attribs[0] as T; 
     } 

     return result; 
    } 

} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     Console.WriteLine("Repository Factory Example \n\n"); 

     Business.Factory.RepositoryFactory factory = new Business.Factory.RepositoryFactory(); 

     // Get a 64 9C2 repository 
     var repo9c2 = factory.GetRepository(FormTypes.Form64_9C2); 
     Console.WriteLine(repo9c2); 
    } 
} 

Benim sorun:

Form64_9C2Repository

public class Form64_9C2Repository : IRepository<Form64_9C2> 
{ 
    public bool Create(IEnumerable<Form64_9C2> entities) 
    { 
     throw new NotImplementedException(); 
    } 

    public bool Delete(IEnumerable<Form64_9C2> entities) 
    { 
     throw new NotImplementedException(); 
    } 

    public IEnumerable<Form64_9C2> Read() 
    { 
     throw new NotImplementedException(); 
    } 

    public bool Update(IEnumerable<Form64_9C2> entities) 
    { 
     throw new NotImplementedException(); 
    } 
} 

IEntity

public interface IEntity { } 

Form64_9C2 (saplama)

public class Form64_9C2 : IEntity { } 

olarak tüm çağrı benim type her zaman null için çözüyor. NotImplementedException almak için bekliyorum, ancak geçerli bir formType sahip olmadığından ArgumentException almak alıyorum.

enter image description here

önce uygulamaya IRepository<T> benim type/repository başarıyla (çalışma kod here), herhangi bir fikir yarattı ediliyordu? Sadece fabrikalar, jenerikler ve benzerleriyle uğraşmaya başladım - eğer yanlış bir şey yapıyorumsa lütfen öneride bulunun!

cevap

5

Kodunuz bu hat derlemek olmadığı için tam olarak aynı nedenden dolayı çalışmaz: IRepository<Form64_9C2> bile Form64_9C2IEntity uygulayan olarak

IRepository<IEntity> repo = new Form64_9C2Repository(); 

Temelde IRepository<IEntity> aynı değildir.

public interface IRepository<out T> where T : class, IEntity 
{ 
    IEnumerable<T> Read();  
} 

Ama ne yazık ki bu sadece değil parametre olarak, yöntemleri için dönüş türü olarak görünebilir anlamına gelir: IRepository arabirimde T jenerik parametre covariant olsaydı

Bu

çalışmış olabilir. Update, Delete ve Create yöntemleriniz için no-go. Elbette böyle bir yapı tanımlayabiliriz:

public interface IReadonlyRepository<out T> where T : class, IEntity 
{ 
    IEnumerable<T> Read();  
} 

public interface IRepository<T>: IReadonlyRepository<T> where T : class, IEntity 
{ 
    bool Update(IEnumerable<T> entities); 
    bool Delete(IEnumerable<T> entities); 
    bool Create(IEnumerable<T> entities); 
} 

ve GetRepository yöntemi bir IReadonlyRepository<IEntity> dönmek var.

bu sizin için işe yaramazsa doğru döküm gerçekleştirmek, böylece beton varlık türünü belirtmek için ek bir parametre gerekir: depo tipi Eğer belirterek ek olarak çağrılırken

public IRepository<TEntity> GetRepository<TEntity>(FormTypes formType) where TEntity: class, IEntity 
    { 
     // Represents the IRepository that should be created, based on the form type passed 
     var typeToCreate = formType.GetAttribute<EnumTypeAttribute>().Type; 

     // return an instance of the form type repository 
     IRepository<TEntity> type = Activator.CreateInstance(typeToCreate) as IRepository<TEntity>; 

     if (type != null) 
      return type; 

     throw new ArgumentException(string.Format("No repository found for {0}", nameof(formType))); 
    } 
} 

ve varlık türünü belirtmeniz gerekir. sadece t 'çok değiştirir dışarı `yapım

var repo9c2 = factory.GetRepository<Form64_9C2>(FormTypes.Form64_9C2); 
+0

vay - neden :(ben gerçekten anlamıyorum gerçi yazık ki tüm CRUD için bir depo çözmek mümkün istedim Sadece R değil. Gördüğün gibi bir yol kattığını görüyorum. nal parametresi. Bir depoyu çatışan bir varlıkla çağırmaktan kaçınmak için depolarımı ve ilişkili birliğini "birlikte" tutmayı umuyordum. Teşekkürler +1, kısa bir süre içinde gerçekleştirmeyi umduğum şeye daha benzer bir şey bulamadığımı kabul ediyorum. – Kritner

İlgili konular