2011-06-20 13 views
8

मेरे पास आंतरिक कन्स्ट्रक्टर वाला एक वर्ग है और इसे एकता (2.0) से हल करना चाहते हैं।यूनिटीकॉन्टेनर और आंतरिक कन्स्ट्रक्टर

public class MyClass { 
    internal MyClass(IService service) { 
    } 
} 

तो मैं

_container.Resolve<MyClass>(); 

कर रहा हूँ जब मैं करता हूँ तो मैं एक अपवाद

Exception is: InvalidOperationException - The type MyClass cannot be constructed. 

IService पंजीकृत किया गया है और केवल समस्या यह है कि निर्माता आंतरिक है है। मैं वास्तव में यह कक्षा सार्वजनिक होना चाहता हूं, लेकिन मैं चाहता हूं कि यह केवल एक कारखाने के माध्यम से रचनात्मक हो (जिसमें मैं वास्तव में container.Resolve<MyClass>() पर कॉल कर रहा हूं)।

क्या यूनिटी को आंतरिक कन्स्ट्रक्टर देखने का कोई तरीका है? InternalsVisibleTo या कुछ की तरह?

+0

आप इस सीटीआर को सार्वजनिक क्यों नहीं बनाना चाहते हैं? क्या आप एक पुन: प्रयोज्य पुस्तकालय बना रहे हैं? – Steven

उत्तर

8

मैं एक खोदा अंधेरा करना है:

क्या भी काम करेगा पीछा कर रहा है इस उद्देश्य के लिए आप एकता कैसे बढ़ा सकते हैं, और कुछ रोचक जानकारी मिली।

सबसे पहले, ऐसा लगता है कि एकता आंतरिक रूप से IConstructorSelectorPolicy को हल करके उपयोग करने के लिए कौन सा कन्स्ट्रक्टर चुनती है।एकता में शामिल public abstract class ConstructorSelectorPolicyBase<TInjectionConstructorMarkerAttribute> जो इस मणि भी शामिल है,:

/// <summary> 
/// Choose the constructor to call for the given type. 
/// </summary> 
/// <param name="context">Current build context</param> 
/// <param name="resolverPolicyDestination">The <see cref='IPolicyList'/> to add any 
/// generated resolver objects into.</param> 
/// <returns>The chosen constructor.</returns> 
public SelectedConstructor SelectConstructor(IBuilderContext context, IPolicyList resolverPolicyDestination) 
{ 
    Type typeToConstruct = context.BuildKey.Type; 
    ConstructorInfo ctor = FindInjectionConstructor(typeToConstruct) ?? FindLongestConstructor(typeToConstruct); 
    if (ctor != null) 
    { 
     return CreateSelectedConstructor(context, resolverPolicyDestination, ctor); 
    } 
    return null; 
} 

FindInjectionConstructor और कंपनी इस वर्ग के जो अंततः Type.GetConstructors (कोई पैरामीटर है, जो केवल public कंस्ट्रक्टर्स रिटर्न के साथ अधिभार) बुला अंत में private static तरीके हैं। यह मुझे बताता है कि यदि आप अपनी खुद की कन्स्ट्रक्टर चयनकर्ता नीति का उपयोग करने के लिए एकता की व्यवस्था कर सकते हैं, जो किसी भी निर्माता का चयन करने में सक्षम होगा, तो आप सुनहरे हैं।

वहाँ good documentation कैसे बनाने के लिए और अपने स्वयं के कंटेनर एक्सटेंशन का उपयोग करने के बारे में है, इसलिए मुझे लगता है कि यह अपनी खुद की CustomConstructorSelectorPolicy कि DefaultUnityConstructorSelectorPolicy के संबंधित भाग (जो सार आधार वर्ग से निकला भी शामिल है और जब तक आप डिफ़ॉल्ट है बनाने के लिए संभव है कुछ और पंजीकृत करें) और ConstructorSelectorPolicyBase (सीधे से प्राप्त करना शायद अच्छी तरह से काम नहीं करेगा क्योंकि मुख्य विधियां virtual नहीं हैं, लेकिन आप कोड का पुन: उपयोग कर सकते हैं)।

इसलिए मैं कहता हूं कि यह मामूली मात्रा में परेशानी के साथ काम करने योग्य है, लेकिन अंतिम परिणाम इंजीनियरिंग दृष्टिकोण से काफी "शुद्ध" होगा।

+0

कस्टम 'आईसीओन्स्ट्रक्टर चयनकर्ता नीति' https://msdn.microsoft.com/en-us/library/dn178464(v=pandp.30) के उपयोग का एक उदाहरण यहां दिया गया है। aspx – altso

0

यह संभव है कि वर्कअराउंड/हैक्स जो आपको यूनिटी 9 के साथ ऐसा करने की अनुमति दें, मुझे कोई जानकारी नहीं है), लेकिन सामान्य रूप से यदि आप कक्षा को यूनिटी (या किसी भी आईओसी कंटेनर) द्वारा प्रबंधित करना चाहते हैं, तो यह सामान्य है एक सार्वजनिक कन्स्ट्रक्टर के साथ सार्वजनिक होने की जरूरत है।

एक विकल्प एक अमूर्त कारखाना बनाना हो सकता है जो उस वर्ग को बनाता है जिसमें सार्वजनिक निर्माता होता है, और कक्षा के निर्माता को आंतरिक रखता है। नकारात्मकता तब आपका कारखाना एकता द्वारा प्रबंधित किया जाएगा, लेकिन आपकी कक्षा स्वयं नहीं होगी।

+1

"इसे सार्वजनिक कन्स्ट्रक्टर के साथ सार्वजनिक होना चाहिए।" - यह गलत है, एकता सार्वजनिक रचनाकारों के साथ आंतरिक कक्षाओं के साथ पूरी तरह से काम करती है। यही वह मामला है जब मैं आईओसी के साथ अपनी आंतरिक निर्भरताओं का प्रबंधन करना चाहता हूं। मैंने जो किया है वह एक अमूर्त कारखाना है। और इसके भीतर मैं MyClass का एक उदाहरण बनाना चाहता हूं। मैं नया MyClass (_container.Resolve ()) कर सकता हूं, लेकिन इसे मैन्युअल रूप से नहीं करना चाहता। – Shaddix

5

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

मैं वास्तव में, इस वर्ग के सार्वजनिक होने के लिए चाहते लेकिन मैं इसे, केवल एक कारखाने

उस मामले में के माध्यम से creatable होना एक कारखाने का निर्माण करना चाहते:

public class MyClassFactory : IMyClassFactory 
{ 
    private readonly IService service; 

    public MyClassFactory(IService service) 
    { 
     this.service = service; 
    } 

    MyClass IMyClassFactory.CreateNew() 
    { 
     return new MyClass(this.service); 
    } 
} 

और पंजीकरण:

_container.Register<IMyClassFactory, MyClassFactory>(); 

और हल करें:

_container.Resolve<IMyClassFactory>().CreateNew(); 

तुम भी उपयोग कर सकते हैं एकता के InjectionFactory:

container.Register<MyClass>(new InjectionFactory(c => 
{ 
    return new MyClass(c.Resolve<IService>()); 
})); 

इसके लिए विधानसभा कि रखती है इस कोड को विधानसभा कि MyClass धारण के आंतरिक भागों को देखने के लिए सक्षम होना चाहिए काम करने के लिए। दूसरे शब्दों में MyClass असेंबली InternalsVisibleTo के साथ चिह्नित किया जाना चाहिए।

public static class MyClassFactory 
{ 
    public static MyClass CreateNew(IService service) 
    { 
     return new MyClass(service); 
    } 
} 

container.Register<MyClass>(new InjectionFactory(c => 
{ 
    return MyClassFactory.Create(c.Resolve<IService>()); 
})); 

यद्यपि आप निर्माता सार्वजनिक करने की आवश्यकता नहीं है, यह एक शानदार तरीका अपने कोड :-)

+0

धन्यवाद, यह लगभग वही है जो मैं कर रहा हूं :) मैं बस उस कारखाने को बदलना पसंद नहीं करता हर बार MyClass निर्भरता बदल जाएगी। तो, किसी भी तरह से एकता के माध्यम से इसे सीधे करने का कोई तरीका खोजना – Shaddix

2

बस यह वर्ग आंतरिक और निर्माता सार्वजनिक ...

  1. इंटरफ़ेस सार्वजनिक
  2. कक्षा आंतरिक
  3. वर्ग जनता के निर्माता।
संबंधित मुद्दे