2012-01-13 18 views
16

का उपयोग कर कई रचनाकारों के साथ उदाहरण को हल करें मैं एकता का उपयोग करके कक्षा का एक उदाहरण बनाना चाहता हूं जहां वर्ग के समान संख्या वाले पैरामीटर वाले दो निर्माता हैं।एकता

यहाँ इन्स्टेन्शियशन है:

_unityContainer.Resolve<IGradeType>(new ParameterOverride("gradeTypeStringFromXmlFile", gradeTypeStringFromXmlFile)); 

और यहाँ निर्माता ये हैं:

public GradeType(string gradeTypeStringFromXmlFile) 
    { 
     _gradeTypeStringFromXmlFile = gradeTypeStringFromXmlFile; 
    } 

    public GradeType(Enum.GradeType gradeType) 
    { 
     _gradeType = gradeType; 
    } 

यदि मैं यह करने की कोशिश मैं एक अपवाद कह प्रकार GradeType लंबाई 1 के कई निर्माताओं है मिल को असंबद्ध करने में असमर्थ।

मैं इसे एक निर्माता के साथ एक इंटीरियर [इंजेक्शन कॉन्स्ट्रक्टर] पर सेट कर सकता हूं ताकि यह एक के साथ काम कर सके, लेकिन फिर मैं अन्य कन्स्ट्रक्टर का उपयोग करके एकता के साथ एक उदाहरण नहीं बना सकता।

क्या यह बराबर संख्या के पैरामीटर वाले एकाधिक कन्स्ट्रक्टर रखने का कोई तरीका है और अभी भी उदाहरण बनाने के लिए एकता का उपयोग करें?

+0

क्लास बनाने से पहले ग्रेड टाइप टाइपिंग पर 'Enum.Parse' का उपयोग क्यों नहीं करें? – jgauffin

+0

यह सिर्फ एक सहज डिजाइन की तरह लगता है कि ग्रेड टाइप क्लास स्ट्रिंग को परिवर्तित करता है। – FatAlbert

+1

यह मेरे लिए एक नाजुक समाधान प्रतीत होता है क्योंकि कोई भी मौजूदा मूल्य या तो अपवाद फेंक देगा या कोई त्रुटि छुपाएगा। – jgauffin

उत्तर

26

हां यह एकता बताना संभव है कि किस रचनाकार का उपयोग करना चाहिए, लेकिन आप केवल तब ही ऐसा कर सकते हैं जब आप InjectionConstructor के साथ अपना प्रकार पंजीकृत करते हैं। यदि आप दोनों कन्स्ट्रक्टर का उपयोग करना चाहते हैं तो यह भी जटिल है क्योंकि आपको अपने पंजीकरण का नाम देना होगा और हल करते समय उस नाम का उपयोग करना होगा।

नमूना एकता संस्करण 2.1.505 के साथ बनाया गया:

var continer = new UnityContainer(); 

continer.RegisterType<IGradeType, GradeType>("stringConstructor", 
    new InjectionConstructor(typeof(string))); 

continer.RegisterType<IGradeType, GradeType>("enumConstructor", 
    new InjectionConstructor(typeof(EnumGradeType))); 

IGradeType stringGradeType = continer.Resolve<IGradeType>("stringContructor" , 
    new DependencyOverride(typeof(string), "some string")); 

IGradeType enumGradeType = continer.Resolve<IGradeType>("enumConstructor", 
    new DependencyOverride(typeof(EnumGradeType), EnumGradeType.Value)); 
+0

बस जो मैं खोज रहा था! धन्यवाद – FatAlbert

+1

एक प्रश्न: निर्भरता को ओवरराइड करते समय हमें कंटेनर पर स्पष्ट रूप से हल करने के लिए मजबूर होना पड़ता है? लेकिन स्पष्ट रूप से कंटेनर को कॉल करना बुरा नहीं है। अपने आवेदन कोड में पुन: प्रयास करें? ओउप्स, वास्तव में दो प्रश्न ;-) – Legends

0

एक कन्स्ट्रक्टर को हटाएं, और स्ट्रिंग को enum, या इसके विपरीत, और फिर कंटेनर का उपयोग करके हल करें।

+0

आप एक पंख को एक स्ट्रिंग नहीं डाल सकते हैं। – jgauffin

+0

Enum.Parse - जैसा कि आपने कहा – Jason

+0

एक्सएमएल से स्ट्रिंग enum से पूरी तरह से अलग है (स्ट्रिंग स्वीडिश में है)। हालांकि, मैं जो पूछ रहा हूं वह यह है कि यदि समान संख्या में पैरामीटर वाले एकाधिक कन्स्ट्रक्टर हैं और अभी भी उदाहरण बनाने के लिए एकता का उपयोग करना संभव है? – FatAlbert

1

प्रतिबिंब का उपयोग करने और Strategy Pattern निम्नलिखित एक वैकल्पिक विकल्प। अपने GradeType कक्षा में)

public class StringArg : ConstructorArgs 
{ 
    public string _gradeTypeStringFromXmlFile { get; set; } 

    public StringArg (string gradeTypeStringFromXmlFile) 
    { 
     this._gradeTypeStringFromXmlFile = gradeTypeStringFromXmlFile ; 
    } 
} 

public class EnumArg : ConstructorArgs 
{ 
    public Enum.GradeType _gradeType { get; set; } 

    public EnumArg (Enum.GradeType gradeType) 
    { 
     this._gradeType = gradeType ; 
    } 
} 

3 अब तरीकों बनाएँ:

1) कंस्ट्रक्टर्स तर्क

public abstract class ConstructorArgs 
{ 
} 

2) विभिन्न ठोस तर्क वर्गों में से एक दृश्य बनाएँ के लिए एक आधार वर्ग बनाएं प्रतिबिंब के लिए आवश्यक है। ParseArguments गुणों के लिए तर्क स्कैन करता है और इसे ढूंढने वाले प्रत्येक के लिए, यह सेटप्रोपर्टी का उपयोग करके ग्रेड टाइप की संबंधित संपत्ति को अपना मान देता है।चूंकि यह मिलान के लिए संपत्ति नाम का उपयोग करता है, यह दोनों GradeType और ठोस ConstructorArgs भर में एक ही संपत्ति का नाम रखने के लिए महत्वपूर्ण है:

 private void SetProperty(String propertyName, object value) 
     { 
      var property = this.GetType().GetProperty(propertyName); 
      if (property != null) 
       property.SetValue(this, value); 
     } 
     private void ParseArguments(ConstructorArgs args) 
     { 
      var properties = args.GetType().GetProperties(); 
      foreach (PropertyInfo propertyInfo in properties) 
      { 
       this.SetProperty(propertyInfo.Name, 
        args.GetType().GetProperty(propertyInfo.Name).GetValue(args)); 
      } 
     } 

4) अपने GradeType कक्षा में संबंधित गुण (मन बनाते हैं तो आपको ठीक उसी नाम और प्रकार है कि आप ठोस ConstructorArgs में प्रयोग किया जाता का उपयोग, लेकिन आप प्रकार ConstructorArgs की एक पैरामीटर के साथ अपना GradeType वर्ग के लिए किसी भी उपयोग संशोधक आप की तरह)

public string _gradeTypeStringFromXmlFile { get; set; } 
    public Enum.GradeType _gradeType { get; set; } 

5) एक निर्माता बनाएं उपयोग कर सकते हैं:

public GradeType(ConstructorArgs args) 
    { 
     this.ParseArguments(args); 
    } 

6) अब आप एकता में GradeType एक भी निर्माता का उपयोग कर रजिस्टर कर सकते हैं, लेकिन आप तर्क के रूप में विभिन्न प्रकार में पारित कर सकते हैं जब आप उसे ठीक करने:

_unityContainer.RegisterType<IGradeType, GradeType>(
     new InjectionConstructor(typeof(ConstructorArgs))); 

    var args1 = new StringArg(gradeTypeStringFromXmlFile); // string 
    IGradeType gradeType1 = _unityContainer.Resolve<IGradeType>(
     new ResolverOverride[]{new ParameterOverride("args", args1)}); 

    var args2 = new EnumArg(gradeType); // enum 
    IGradeType gradeType2 = _unityContainer.Resolve<IGradeType>(
     new ResolverOverride[]{new ParameterOverride("args", args2)}); 

आप की योजना बना रहे हैं, तो बार-बार एक चरण में अपने प्रकार का समाधान वह दृष्टिकोण आदर्श नहीं हो सकता है, क्योंकि प्रतिबिंब प्रदर्शन प्रदर्शन के साथ आता है।

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