स्ट्रक्चुरपेज़ - काम के लिए एक त्वरित संदर्भ (2/3)

स्ट्रक्चुरपेज़ के बारे में पहली पोस्ट की निरंतरता

पहले भाग में शामिल विषय:

इस भाग में हम बात करेंगे:


कंस्ट्रक्टर्स


IoC कंटेनरों में निर्भरता को हल करने के संबंध में वास्तविक प्रोग्रामिंग में एक बहुत महत्वपूर्ण सवाल, उन कक्षाओं के बारे में क्या है जिनके पास कई निर्माता हैं। उन्हें कैसे आरंभ किया जाए, कैसे मापदंडों को सेट किया जाए, कैसे संशोधित किया जाए इत्यादि और आगे। मुझे उम्मीद है कि नीचे दिए गए अधिकांश सवालों के जवाब दिए जाएंगे। स्ट्रक्चर्सपाइप वास्तव में शक्तिशाली और लचीला है।

इससे पहले कि आप ढांचे की क्षमताओं का वर्णन करना शुरू करें, आपको परीक्षण कक्षाओं के बारे में बात करनी होगी। इस बार वे अधिक कठिन होंगे। इनहेरिटेंस, कंस्ट्रक्टर सरल प्रकार के साथ, यौगिक वाले।



तो, हमारे पास निम्न वर्ग हैं:
public interface IClassA : IClass { int A { get; set; } } public interface IClassB : IClass {} public class ClassA : IClassA { public int A { get; set; } public int B { get; set; } public Class1 Class1 { get; set; } [DefaultConstructor] public ClassA() {} public ClassA(int a) { A = a; } } public class ClassB : IClassB { public IClassA ClassA; public ClassB(IClassA classA) { ClassA = classA; } } public class ClassM : IClassA { public int A { get; set; } public ClassM(int a) { A = a; } public ClassM(int a, int b) { A = a + b; } } 

वे इस समय कुछ अतिरेक के साथ हैं, जो कहानी में थोड़ा आगे आते हैं।

तो, चलो सबसे सरल विकल्पों के साथ शुरू करते हैं।

सरल प्रकार


आइए क्लासए क्लास के साथ शुरू करें, जिसमें एक कंस्ट्रक्टर एक पूर्णांक पैरामीटर को स्वीकार करता है।
 public class WithSimpeArguments { public IContainer Container; public WithSimpeArguments() { Container = new Container(x => x.For<IClassA>().Use<ClassA>() .Ctor<int>().Is(5) ); } } 

जैसा कि आप उदाहरण से देख सकते हैं, निर्माणकर्ता को मूल्यों के साथ आरंभ करने का एक संकेत पहले से ही परिचित घोषणा में जोड़ा जाता है। इस मामले में, कंस्ट्रक्टर घोषणा एक सरलीकृत योजना का पालन करती है, क्योंकि टाइप इंट का केवल एक पैरामीटर है। आरंभीकरण प्रक्रिया में, हमने तुरंत मूल्य का संकेत दिया। उसी समय, स्ट्रक्चुरपेज़ आपको बताएगा कि मूल्य एक पूर्णांक होना चाहिए।

ऑपरेशन की जांच करने के लिए, आप पहले से ही परिचित कोड को कॉल कर सकते हैं
 private static string WithSimpleArgumentsExample() { var container = new WithSimpeArguments().Container; var classA = (ClassA) container.GetInstance<IClassA>(); return classA.A.ToString(); } 

परिणामस्वरूप, नंबर 5 कंसोल पर प्रदर्शित होगा।

हम मामले के लिए उदाहरण को जटिल करते हैं जब हमारे पास कंस्ट्रक्टर में एक ही प्रकार के दो पैरामीटर होते हैं। प्रायोगिक कक्षा के रूप में क्लासएम।
 public class WithMultipleSimpeArguments { public IContainer Container; public WithMultipleSimpeArguments() { Container = new Container(x => x.For<IClassA>().Use<ClassM>() .Ctor<int>("a").Is(6) .Ctor<int>("b").Is(5)); } } 

अब निर्माण। Ctor <int> ("a")। (6) को तर्क के नाम से पूरक किया गया है, ताकि रूपरेखा तर्कों के मूल्यों से सटीक रूप से मेल खा सके। फ्रेमवर्क हमेशा सबसे "लालची" कंस्ट्रक्टर को पाता है और चाहता है कि सभी तर्कों को आरंभीकृत किया जाए। आप कक्षा के वर्तमान कार्यान्वयन में दूसरे तर्क के लिए मान सेट करने से चूक नहीं सकते। लेकिन आप स्ट्रक्चर्सपाइप को बता सकते हैं कि कौन सा कंस्ट्रक्टर डिफ़ॉल्ट रूप से उपयोग करना है, इसके लिए आपको डिफॉल्टकॉन्स्ट्रक्टर विशेषता का उपयोग करना होगा।

डिफ़ॉल्ट निर्माता


DefaultConstructor विशेषता आपको स्पष्ट रूप से यह निर्दिष्ट करने की अनुमति देती है कि किस निर्माता को कक्षा को तत्काल उपयोग करने के लिए उपयोग करना है। ताकि पिछले उदाहरण में चर b की घोषणा को छोड़ना संभव होगा और इस प्रक्रिया में कुछ भी नहीं गिर गया।
 public class ClassM : IClassA { public int A { get; set; } [DefaultConstructor] public ClassM(int a) { A = a; } public ClassM(int a, int b) { A = a + b; } } 

अब आप एक पैरामीटर के साथ कंस्ट्रक्टर का उपयोग कर सकते हैं

यौगिक प्रकार


यौगिक प्रकारों के साथ काम करना बहुत आसान है, क्योंकि स्ट्रक्चुरपेज़ स्वयं यौगिक प्रकारों द्वारा सभी निर्भरता का पता लगाता है और हल करता है। यानी यदि आप कक्षाओं में शुरुआत को देखते हैं, तो आप देख सकते हैं कि क्लासबी क्लास को क्लास क्लास द्वारा आरंभीकृत किया गया है। अब हम देखते हैं कि इस प्रकार की निर्भरता को हल करने के लिए कुछ विशेष की आवश्यकता नहीं है।
 public class WithObjectArguments { public IContainer Container; public WithObjectArguments() { Container = new Container(x => { x.For<IClassA>().Use<ClassA>().Ctor<int>().Is(5); x.For<IClassB>().Use<ClassB>(); }); } } 

जैसा कि आप उदाहरण से देख सकते हैं, कोई अतिरिक्त ऑपरेटर लागू नहीं हैं। लेकिन आप क्लासबी क्लास का अनुरोध कर सकते हैं, जिसे क्लासए द्वारा आरंभ किया जाएगा।
 private static string WithObjectArgumentsExample() { var container = new WithObjectArguments().Container; var classA = (ClassB) container.GetInstance<IClassB>(); return classA.ClassA.A.ToString(); } 

5 नंबर स्क्रीन पर प्रदर्शित किया जाएगा।

कास्टिंग टाइप करें


यदि आप क्लासबी क्लास की घोषणा को देखते हैं, तो आप देखेंगे कि कंस्ट्रक्टर में चर एक विशिष्ट प्रकार है, न कि एक इंटरफ़ेस। हम वर्ग को फिर से लिखते हैं ताकि इंटरफ़ेस के बजाय, निर्माता क्लासए क्लास को स्वीकार कर ले
 public class ClassB : IClassB { public ClassB(ClassA classA) { ClassA = classA; } } 

अब टाइप बाइंडिंग नहीं होगी, क्योंकि कंटेनर रजिस्टर करता है और एक ही डेटा टाइप देता है। हमारे मामले में, यह IClassA है।
 private static string WithObjectArgumentsForwardingAndWiringExample() { var container = new WithObjectArgumentsForwarding().Container; var classB = (ClassB) container.GetInstance<IClassB>(); return classB.ClassA.A.ToString(); } 

यह कोड 0 वापस आ जाएगा, क्योंकि क्लासए क्लास के लिए डिफ़ॉल्ट कंस्ट्रक्टर को कॉल किया जाएगा, कोई बाध्यकारी नहीं हुआ है।

आपने अनुमान लगाया कि यह कोई समस्या नहीं है। आप यह निर्दिष्ट कर सकते हैं कि स्ट्रक्च्योरपाइप किस ओर ले जा सकता है यह फ़ॉर्वर्ड कमांड का उपयोग करके किया जाता है जिसे स्रोत प्रकार और वांछित निर्दिष्ट करना होगा।
 public class WithObjectArgumentsForwarding { public IContainer Container; public WithObjectArgumentsForwarding() { Container = new Container(x => { x.For<IClassA>().Use<ClassA>().Ctor<int>().Is(5); x.Forward<IClassA, ClassA>(); x.For<IClassB>().Use<ClassB>(); }); } } 

अब आप WithObjectArgumentsForwardingAndWiringExample विधि को कॉल कर सकते हैं और प्रतिक्रिया में 5 प्राप्त कर सकते हैं।

तर्क को परिभाषित करना


सबसे अधिक बार, पहले से ही एक वर्ग के लिए तर्क ढूंढना और निर्धारित करना संभव नहीं है, वे केवल आवश्यक वर्ग बनाने के समय ही ज्ञात हो जाते हैं। और चूंकि ये प्रोग्राम लिखने के काम के दिन हैं, इसलिए जिस समय कक्षा बनाई गई थी उस समय बहस करने के लिए समर्थन मदद नहीं कर सकता था, लेकिन स्ट्रक्चरपार्ट में दिखाई देगा।

नए तर्क मूल्यों के साथ एक वर्ग को बुलाने की प्रक्रिया योदा मास्टर की भाषा में संवाद करने के समान है, लेकिन यह डीएसएल की विशिष्टता है। तकनीकी सीमाएं मेरा मतलब है।

तो, चलिए क्लासबी क्लास को नए क्लासए क्लास के साथ बुलाना चाहते हैं। ऐसा करने के लिए, आपको एक कथन की आवश्यकता है।
 private static string WithObjectArgumentsOverridingExample() { var container = new WithObjectArgumentsForwarding().Container; var classB = (ClassB) container .With(new ClassA(8)) .GetInstance<IClassB>(); return classB.ClassA.A.ToString(); } 

चूंकि रूपरेखा, इस मामले में, स्पष्ट रूप से यह निर्धारित कर सकती है कि किस तर्क को वर्ग उदाहरण मैप किया जाना चाहिए, यह तर्क का नाम निर्दिष्ट करने के लिए आवश्यक नहीं है।

यदि आपको वर्ग के लिए बड़ी संख्या में तर्क निर्दिष्ट करने की आवश्यकता है, तो आपको पैरामीटर नाम और इसके मूल्य के साथ बड़ी संख्या में तरीकों का उपयोग करने की आवश्यकता है।
 private static string WithObjectArgumentsOverridingExample() { var container = new WithObjectArgumentsForwarding().Container; var classB = (ClassB) container .With(new ClassA(8)) .With("s").EqualTo(5) .GetInstance<IClassB>(); return classB.ClassA.A.ToString(); } 

अब, डिजाइनरों के साथ काम, मुझे लगता है कि आपके आवेदन में लगभग सभी वास्तुशिल्प दृष्टिकोणों को हल करने के लिए पर्याप्त रूप से कवर किया गया है।

गुण


आवश्यक निर्माता मापदंडों के अलावा, वर्ग उदाहरण निर्माण के दौरान वर्ग के गुणों के मूल्यों को निर्धारित करना बहुत अच्छा है। यानी लिखने के बजाय
 var classA = new ClassA(); classA.A = 8; classA.B = 20; 

आप गुणों को बहुत कम और प्रीटियर के रूप में सेट कर सकते हैं:
 var classA = new ClassA { A = 8, B = 20 }; 

StuctureMap के लिए, यह बहुत संभव है, और एक ही सुरुचिपूर्ण और समझने योग्य तरीके से।

सरल संपत्ति सेटिंग


सरलतम मामले में, जैसा कि ऊपर चित्रण में है, आप SetProperty पद्धति का उपयोग करके पैरामीटर सेट कर सकते हैं।
 public class WithArgumentsSetProperty { public IContainer Container; public WithArgumentsSetProperty() { Container = new Container(x => x.For<IClassA>().Use<ClassA>() .Ctor<int>().Is(5) .SetProperty(p => { pA = 8; pB = 20; })); } } 

जैसा कि आप उदाहरण से देख सकते हैं, गुणों को दृढ़ता से टाइप किया गया है और आप इंटेलीजेंस संकेत का उपयोग कर सकते हैं, अर्थात। गुण सेट करना आसान और सरल है। यह स्पष्ट है कि सभी संपत्तियों को सेट नहीं किया जा सकता है, लेकिन केवल वे जिन्हें आप वर्ग के एक उदाहरण के निर्माण के चरण में आरंभ करना चाहते हैं।

अंतर्निहित संपत्ति परिभाषा


इनलाइन पैरामीटर सेटिंग का उपयोग करने के लिए, सेटर विधि का उपयोग किया जाता है। इस पद्धति का उपयोग करके, आप एक समय में एक पैरामीटर के लिए मान सेट कर सकते हैं। चूंकि विधि का तर्क एक फ़ंक्शन है।

सरलतम बात यह है कि प्रारंभ के लिए पैरामीटर को स्पष्ट रूप से सेट करें।
 public class WithArgumentsSetterExplicit { public IContainer Container; public WithArgumentsSetterExplicit() { Container = new Container(x => { x.For<IClass1>().Use<Class1>(); x.For<IClassA>().Use<ClassA>() .Ctor<int>().Is(5) .Setter(c => c.Class1).Is(new Class1()); }); } } 

उदाहरण से पता चलता है कि संपत्ति Class1 को हमेशा नए वर्ग Class1 द्वारा प्रारंभ किया जाएगा। इस तरह के रिकॉर्ड को लागू किया जाना चाहिए यदि वर्ग में एक ही प्रकार की एक से अधिक संपत्ति हो। यदि आपके पास दिए गए प्रकार की केवल एक संपत्ति है, तो फ्रेमवर्क स्वतंत्र रूप से यह निर्धारित करने में सक्षम होगा कि किस पैरामीटर को पारित पैरामीटर के मूल्य को निर्दिष्ट करना है।

तो, संपत्ति के प्रारंभिककरण का मतलब है।
 public class WithArgumentsSetterImplicit { public IContainer Container; public WithArgumentsSetterImplicit() { Container = new Container(x => { x.For<IClass1>().Use<Class1>(); x.For<IClassA>().Use<ClassA>() .Ctor<int>().Is(5) .Setter<Class1>().Is(new Class1()); }); } } 

इस उदाहरण में, हमने संपत्ति का नाम निर्दिष्ट नहीं किया, लेकिन सब कुछ ठीक हो गया, क्योंकि क्लास 1 की केवल एक संपत्ति है।

एक रूपरेखा के साथ गुण सेट करना


चूंकि स्ट्रक्चुरपेज़ स्वचालित रूप से क्लास इंस्टेंस को कंस्ट्रक्टर के तर्कों में बदल सकता है, क्या यह स्वचालित रूप से क्लास प्रॉपर्टीज को पॉप्युलेट कर सकता है?

बेशक वह कर सकता है!

लेकिन निश्चित रूप से वह ऐसा नहीं करेगा और सभी क्षेत्रों के लिए नहीं, बल्कि केवल उन लोगों के लिए किया जाएगा, जिन्हें स्वत: पूर्ण होने का संकेत दिया जाएगा।

आप पिछले उदाहरण को संशोधित कर सकते हैं, ताकि संरचना के आधार पर संपत्ति निर्भरता हल हो और नियंत्रित हो।
 public class WithArgumentsSetterImplicitDefault { public IContainer Container; public WithArgumentsSetterImplicitDefault() { Container = new Container(x => { x.For<IClass1>().Use<Class1>(); x.For<IClassA>().Use<ClassA>() .Ctor<int>().Is(5) .Setter<Class1>().IsTheDefault(); }); } } 

उदाहरण में, एक नया IsTheDefault विधि दिखाई दी , जो अपने स्वयं के साधनों के साथ निर्भरता को हल करने के लिए रूपरेखा बताती है। यानी इस स्थिति में, कक्षा 1 में टाइप Class1 की एक संपत्ति बनाई जाएगी और यह निर्दिष्ट किया जाएगा कि Class1 कैसे पंजीकृत है।

बैच पैरामीटर इनिशियलाइज़ेशन भी है, जब यह कहा जा सकता है कि एक निश्चित प्रकार के सभी गुणों को डिफ़ॉल्ट मानों के साथ आरंभीकृत किया जाना चाहिए। ऐसा करने के लिए, SetAllProperties कमांड का उपयोग करें।
 public class WithArgumentsSetterBatchImplicitDefault { public IContainer Container; public WithArgumentsSetterBatchImplicitDefault() { Container = new Container(x => { x.For<IClass1>().Use<Class1>(); x.For<IClassA>().Use<ClassA>() .Ctor<int>().Is(5); x.SetAllProperties(c => c.OfType<Class1>()); }); } } 

इस संकेत के साथ, स्ट्रक्च्योर मैप स्वचालित रूप से उन वर्गों के सभी गुणों को इनिशियलाइज़ कर देगा, जिनके लिए प्रॉपर्टी का प्रकार Class1 है।

मौजूदा कक्षाओं का उन्नयन


कभी-कभी ऐसा होता है कि आप केवल एक तैयार वर्ग प्राप्त कर सकते हैं, बिना किसी तरह इसके निर्माण को प्रभावित करने की क्षमता के। उसी समय, मैं स्वत: मोड में वर्ग फ़ील्ड के ढेर को स्वचालित करना चाहता हूं। और यह स्ट्रक्च्योर मैप के साथ संभव है।

क्लासए को हमारे पास आने दो जो हमारे सिस्टम में नहीं बना है। टाइप 1 की अपनी संपत्ति को इनिशियलाइज़ करना आवश्यक है। सबसे पहले StructureMap सेट करें।
 public class WithArgumentsBuildUp { public IContainer Container; public WithArgumentsBuildUp() { Container = new Container(x => { x.For<IClass1>().Use<Class1>(); x.Forward<IClass1, Class1>(); x.SetAllProperties(c => c.OfType<Class1>()); }); } } 

अब आप बिल्डअप विधि कह सकते हैं , जो उपलब्ध कॉन्फ़िगरेशन के अनुसार, ऑब्जेक्ट को पूरा करेगा।
 var container = new WithArgumentsBuildUp().Container; var classA = new ClassA(14); container.BuildUp(classA); 

दूसरी पंक्ति पर, संपत्ति Class1 = null, बिल्डअप को कॉल करने के बाद, ऑब्जेक्ट पूरी तरह से तैयार है।

जीवन का समय


एक महत्वपूर्ण कारक वस्तु के जीवनकाल को नियंत्रित करने की क्षमता है। कुछ वर्गों के लिए आपको एक ही उदाहरण प्राप्त करने की आवश्यकता है, दूसरों के लिए - हर बार नया। यह कंटेनर में नियमों के निर्माण के दौरान भी नियंत्रित किया जा सकता है।

फ्रेमवर्क सात वस्तु जीवनकाल प्रबंधन नीतियों के साथ संचालित होता है:

चलो एक उदाहरण के रूप में एक साधारण वर्ग का उपयोग करते हुए उनमें से कुछ पर विचार करें।
 public class ClassX : IClassX { public int Counter { get; private set; } public void Increase() { Counter++; } } public interface IClassX {} 

बता दें कि सिंगलटन पहली पंक्ति में हैं।
 public class LifecycleSingleton { public IContainer Container; public LifecycleSingleton() { Container = new Container(x => x.For<IClassX>().LifecycleIs(new SingletonLifecycle()).Use<ClassX>()); Container = new Container(x => x.For<IClassX>().Singleton().Use<ClassX>()); } } 

शॉर्टहैंड विधियों को बुनियादी जीवन नीतियों के लिए परिभाषित किया गया है। यानी आप दोनों सिंगलटन () और लाइफसाइकल (नया सिंगलटन लाइक साइकिल ) () का उपयोग कर सकते हैं।

जाँच के रूप में, आप एक दृश्य उदाहरण का उपयोग कर सकते हैं:
 private static string LifecycleSingleton() { var singleton = new LifecycleSingleton().Container; var classX = (ClassX) singleton.GetInstance<IClassX>(); classX.Increase(); Console.WriteLine(classX.Counter); classX = (ClassX) singleton.GetInstance<IClassX>(); classX.Increase(); Console.WriteLine(classX.Counter); return "done"; } 

परिणामस्वरूप, कंसोल पर डेटा प्रदर्शित किया जाएगा: "1, 2, पूर्ण"। एक साधारण घोषणा के साथ, हमें मिलेगा: "1, 1, पूर्ण।"

किसी एकल थ्रेड के भीतर किसी वर्ग की आवृत्ति संग्रहीत करने के लिए, थ्रेडलोकलस्टोरेज लाइफ़साइकल , या संक्षिप्त रूप HybridHttpOrThreadLocalScoped का उपयोग करें
 public class LifecycleThreadLocal { public IContainer Container; public LifecycleThreadLocal() { Container = new Container(x => x.For<IClassX>() .LifecycleIs(new ThreadLocalStorageLifecycle()) .Use<ClassX>()); Container = new Container(x => x.For<IClassX>() .HybridHttpOrThreadLocalScoped() .Use<ClassX>()); } } 

HttpContextScoped संक्षिप्त नाम HttpContextLifecycle के लिए परिभाषित किया गया है
 public class LifecycleHttpContext { public IContainer Container; public LifecycleHttpContext() { Container = new Container(x => x.For<IClassX>() .LifecycleIs(new HttpContextLifecycle()) .Use<ClassX>()); Container = new Container(x => x.For<IClassX>() .HttpContextScoped() .Use<ClassX>()); } } 

अगले भाग में जारी

Source: https://habr.com/ru/post/In125695/


All Articles