2016-01-04 11 views
5

के साथ क्रिएटइंस्टेंस मैं एक कारखाने के साथ खेलने के लिए कोशिश कर रहा हूं जो एक विधि है जो विधि को पारित होने के आधार पर एक भंडार बनाता है। इस तरह दिखता है:एक्टिवेटर। एक सामान्य भंडार

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

मेरे समस्या:

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 (ठूंठ)

public class Form64_9C2 : IEntity { } 

के रूप में यह सब कॉलिंग मेरा type हमेशा null पर हल हो रहा है। मुझे NotImplementedException प्राप्त करने की उम्मीद है, लेकिन इसके बजाय ArgumentException प्राप्त करने के लिए एक वैध फॉर्म टाइप नहीं है।

enter image description here

पहले लागू करने के IRepository<T> मेरी type/repository सफलतापूर्वक (काम कर कोड here), किसी भी विचार बनाया जा रहा था? मैं केवल कारखानों, जेनेरिक, और इसी तरह के साथ खेलना शुरू कर रहा हूं - इसलिए यदि मैं कुछ गलत तरीके से कर रहा हूं तो कृपया सलाह दें!

उत्तर

5

आपका कोड ठीक उसी कारण है जिसके लिए इस लाइन को संकलित नहीं है के लिए काम नहीं करता:

IRepository<IEntity> repo = new Form64_9C2Repository(); 

मूल रूप से IRepository<IEntity> एक ही रूप में IRepository<Form64_9C2> भले ही Form64_9C2 लागू करता IEntity नहीं है।

यह काम कर सकते थे अगर IRepository इंटरफेस पर T सामान्य पैरामीटर covariant था:

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

लेकिन दुर्भाग्य से इसका मतलब यह होगा कि यह केवल वापसी प्रकार के रूप में तरीकों के लिए, नहीं पैरामीटर के रूप में दिखाई दे सकता है। जो आपके Update, Delete और Create विधियों के लिए कोई नहीं है। आप निश्चित रूप से इस तरह एक संरचना निर्धारित कर सकते हैं:

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

और अपने GetRepository विधि एक IReadonlyRepository<IEntity> वापसी की है।

यदि यह आपके लिए काम नहीं करता है आप ठोस इकाई प्रकार निर्दिष्ट करने के लिए एक अतिरिक्त पैरामीटर की आवश्यकता होगी, ताकि आप सही डाली प्रदर्शन:

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

और जब भंडार प्रकार आप को निर्दिष्ट करने के अलावा बुला इकाई प्रकार निर्दिष्ट करने के लिए की आवश्यकता होगी:। सिर्फ `बनाने बाहर T` एक बहुत बदल जाता है,

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

वाह - हालांकि मैं सच में समझ में नहीं आता क्यों :(दुर्भाग्य से मैं सभी CRUD के लिए भंडार हल करने में सक्षम होना चाहते थे , सिर्फ आर नहीं। मुझे लगता है कि आप ऐसा करने का एक तरीका प्रदान करते हैं, लेकिन एक additio जोड़कर नल पैरामीटर। मैं वास्तव में एक विवादित इकाई के साथ एक निश्चित भंडार को कॉल करने से बचने के लिए अपने भंडार और इसकी संबद्ध इकाई को "एक साथ" रखने की उम्मीद कर रहा था। धन्यवाद +1, मैं जल्द ही स्वीकार कर दूंगा कि मुझे कुछ और ऐसा नहीं लगता है जो मैं वास्तव में पूरा करने की उम्मीद कर रहा था। – Kritner

संबंधित मुद्दे