क्या मैं निर्माता के मापदंडों को एकता के संकल्प () विधि से पारित कर सकता हूं?


91

मैं निर्भरता इंजेक्शन के लिए Microsoft की एकता का उपयोग कर रहा हूं और मैं कुछ इस तरह करना चाहता हूं:

IDataContext context = _unityContainer.Resolve<IDataContext>();
var repositoryA = _unityContainer.Resolve<IRepositoryA>(context); //Same instance of context
var repositoryB = _unityContainer.Resolve<IRepositoryB>(context); //Same instance of context

IDataContext context2 = _unityContainer.Resolve<IDataContext>(); //New instance
var repositoryA2 = _unityContainer.Resolve<IRepositoryA>(context2);

RepositoryAऔर RepositoryBदोनों के पास एक कंस्ट्रक्टर है जो एक IDataContextपैरामीटर लेता है , और मैं चाहता हूं कि एकता उस संदर्भ के साथ रिपॉजिटरी को इनिशियलाइज़ करे कि मैं इसे पास करता हूं। यह भी ध्यान दें कि IDataContextएकता के साथ पंजीकृत नहीं है (मुझे 3 उदाहरण नहीं चाहिए IDataContext)।

जवाबों:


71

आज तक उन्होंने इस कार्यक्षमता को जोड़ा है:

यह यहां नवीनतम गिरावट में है:

http://unity.codeplex.com/SourceControl/changeset/view/33899

इस पर यहाँ चर्चा:

http://unity.codeplex.com/Thread/View.aspx?ThreadId=66434

उदाहरण:

container.Resolve<IFoo>(new ParameterOverrides<Foo> { { "name", "bar" }, { "address", 42 } });"


5
लिंक unity.codeplex.com/SourceControl/changeset/view/33899 सक्रिय नहीं है
एम। कुमारन

2
"क्लास 'Microsoft.Practices.Unity.ParameterOverrides' में टाइप पैरामीटर नहीं हैं"। मैं एकता 3.5 का उपयोग कर रहा हूं; क्या यह कोड केवल एकता के पुराने संस्करण के लिए मान्य है?
थॉमस लेवेस्क

इससे मेरा काम बनता है। नोट: आपकी कक्षा में "नाम" पैरामीटर और "पता" पैरामीटर के साथ एक पैरामीट्रिक निर्माता होना चाहिए। Foo(string name, int address) { ... }
adun

यूनिटी 2.1 का उपयोग करना: container.Resolve<IFoo>(new ParameterOverrides { { "name", "bar" }, { "address", 42 } });
mrfelis

38

<2 सेंट>

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

निर्माता पैरामीटर और IoC के साथ समस्या यह है कि मापदंडों को अंततः उपयोग किए जा रहे कंक्रीट प्रकार से बांधा जाता है, सेवा अनुबंध को परिभाषित करने वाले अनुबंध का हिस्सा होने के विपरीत।

मेरा सुझाव यह होगा कि आप या तो संदर्भ को हल करें, और मेरा मानना ​​है कि यूनिटी के पास आपके लिए एक रास्ता होना चाहिए ताकि आप इसके 3 उदाहरणों का निर्माण करने से बच सकें, या आपको एक फैक्ट्री सेवा पर विचार करना चाहिए जिसके पास आपके पास ऑब्जेक्ट बनाने का एक तरीका है।

उदाहरण के लिए, क्या होगा अगर आप बाद में एक पारंपरिक डेटाबेस पर निर्भर न करने वाले भंडार का निर्माण करने का निर्णय लेते हैं, बल्कि परीक्षण के लिए डमी-डेटा का उत्पादन करने के लिए XML फ़ाइल का उपयोग करते हैं? आप उस कंस्ट्रक्टर को XML सामग्री खिलाने के बारे में कैसे जाएंगे?

IoC कोडिंग के आधार पर आधारित है, ठोस प्रकार के तर्कों के प्रकार और शब्दार्थ में बांधने से, आपने वास्तव में डिकॉपिंग सही ढंग से नहीं किया है, अभी भी एक निर्भरता है।

"यह कोड संभवतः किसी भी प्रकार के भंडार से बात कर सकता है, जब तक कि यह इस इंटरफ़ेस को लागू करता है .... ओह, और डेटा संदर्भ का उपयोग करता है"।

अब, मुझे पता है कि अन्य IoC कंटेनरों को इसके लिए समर्थन है, और मेरे पास यह मेरे पहले संस्करण में भी था, लेकिन मेरी राय में, यह संकल्प कदम के साथ नहीं है।

</ 2 सेंट>


3
मैं आपकी बात देखता हूं और आपसे सहमत हूं, हालांकि मुझे अभी भी एक ही IDataContext के लिए रिपॉजिटरी और रिपोजिटरी के उदाहरणों की आवश्यकता है, जिसे रिपोजिटरी से अलग होने की जरूरत है। यह भी ध्यान दें कि IRepositoryA और IRepositoryB के पास IDataContext की संपत्ति है। मैं नमूना कोड को थोड़ा अपडेट करूंगा।
NotDan

2
महान बिंदु। मैं कंस्ट्रक्टर में एक स्ट्रिंग पैरामीटर जोड़ने वाला था, लेकिन इस बिंदु को देखने के बाद, मैंने इसे एक पूर्ण विकसित वस्तु बनाने का फैसला किया। इसमें केवल इस बिंदु पर स्ट्रिंग शामिल है, लेकिन मैं पहले से ही देख सकता हूं कि मैं इसमें और अधिक उपयोगी गुण कैसे जोड़ सकता हूं
संतोष बेंजामिन

9

धन्यवाद दोस्तों ... मेरा "एक्ज़िस्ट" पोस्ट के समान है। निचे देखो:

        IUnityContainer container = new UnityContainer();
        container.LoadConfiguration();

        _activeDirectoryService = container.Resolve<IActiveDirectoryService>(new ResolverOverride[]
        {
            new ParameterOverride("activeDirectoryServer", "xyz.adserver.com")
        });

5

आप कंटेनर में पहले से पंजीकृत वस्तु का एक उदाहरण प्राप्त करने के लिए ResolveParameter <T> ("नाम") के भीतर अपने इंजेक्शन आर्किटेक्चर के आधार पर InjectionConstructor / InjectionProperty / InjectionMethod का उपयोग कर सकते हैं।

आपके मामले में इस ऑब्जेक्ट को एक नाम के साथ पंजीकृत होना चाहिए, और उसी आग्रह के लिए आपको LifeTimeManager के रूप में कंटेनरकंट्रोलडलाइफ टाइममैनएगर () की आवश्यकता होगी।

_unityContainer.RegisterType<IDataContext,DataContextA>("DataContextA", new ContainerControlledLifeTimeManager());
_unityContainer.RegisterType<IDataContext,DataContextB>("DataContextB");

  var repositoryA = _unityContainer.Resolve<IRepositoryA>(new InjectionConstructor(
new ResolvedParameter<IDataContext>("DataContextA")));

  var repositoryB = _unityContainer.Resolve<IRepositoryB>(new InjectionConstructor(
new ResolvedParameter<IDataContext>("DataContextA")));

  var repositoryA2 = _unityContainer.Resolve<IRepositoryA>(new InjectionConstructor(
new ResolvedParameter<IDataContext>("DataContextB")));

4
क्या आप इस कोड के बारे में निश्चित हैं? यह संकलित नहीं करता है ... Resolveका एक संग्रह लेता है ResolverOverride, और InjectionConstructorएक नहीं है ResolverOverride
थॉमस लेवेस्क

हाँ यह गलत लगता है। हालांकि एकता को इसे इस तरह से डिजाइन करना चाहिए था। यदि पैरामीटर नाम बदलता है तो सब कुछ टूट जाता है
फ्रैंक Q.

3

बहुत ही संक्षिप्त उत्तर है: नहीं। एकता के पास वर्तमान में कंस्ट्रक्टर में मापदंडों को पारित करने का कोई तरीका नहीं है जो निरंतर या इंजेक्शन नहीं हैं, जिसे मैं ढूंढने में सक्षम हूं। IMHO यह एक सबसे बड़ी चीज है जो इसे याद कर रही है, लेकिन मुझे लगता है कि यह डिजाइन के बजाय चूक से है।

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

आप पूर्ण DI से एक छोटा कदम वापस ले सकते हैं और अपने रिपॉजिटरी कार्यान्वयन को अपने स्वयं के डेटा संदर्भों को स्थापित करने के लिए जिम्मेदार बना सकते हैं। संदर्भ उदाहरण को अभी भी कंटेनर से हल किया जा सकता है, लेकिन यह निर्णय लेने के लिए कि कौन सा उपयोग करना है, रिपॉजिटरी के कार्यान्वयन में जाना होगा। यह उतना शुद्ध नहीं है, निश्चित रूप से, लेकिन यह समस्या से छुटकारा दिलाएगा।


1

एक और विकल्प जो आप उपयोग कर सकते हैं (वास्तव में यह नहीं जानते कि यह एक अच्छा अभ्यास है या नहीं) दो कंटेनरों का निर्माण कर रहा है और प्रत्येक के लिए एक उदाहरण दर्ज कर रहा है:

IDataContext context = _unityContainer.Resolve<IDataContext>();
_unityContainer.RegisterInstance(context);
var repositoryA = _unityContainer.Resolve<IRepositoryA>(); //Same instance of context
var repositoryB = _unityContainer.Resolve<IRepositoryB>(); //Same instance of context


//declare _unityContainer2
IDataContext context2 = _unityContainer2.Resolve<IDataContext>(); //New instance
_unityContainer2.RegisterInstance(context2);
var repositoryA2 = _unityContainer2.Resolve<IRepositoryA>(context2); //will retrieve the other instance

आशा है कि यह भी मदद करता है


0

NotDan, मुझे लगता है कि आपने अपने स्वयं के प्रश्न का उत्तर लेससेक को दिया है।

सबसे पहले, मैं एक लाइफटाइम मैनजर का उपयोग कर सकता हूं जो कि एकता बनाने वाले IDataContext के जीवनचक्र और संख्याओं का प्रबंधन करता है।
http://msdn.microsoft.com/en-us/library/cc440953.aspx

ऐसा लगता है कि ContainerControlledLifetimeManagerऑब्जेक्ट आपको उदाहरण प्रबंधन देगा जो आपको चाहिए। उस लाइफटाइम मैनजर के साथ, एकता को सभी वस्तुओं में IDataContext का एक ही उदाहरण जोड़ना चाहिए, जिसके लिए IDataContext निर्भरता की आवश्यकता होती है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.