2011-06-13 12 views
6

मैं यूनिटी कंटेनर में रजिस्टर टाइप विधि का आह्वान करने की कोशिश कर रहा हूं। रजिस्टर टाइप में कुल 16 ओवरराइड हैं (उनमें से कुछ पैरामीटर कुछ प्रकार हैं)।जेनिक्स और ओवरराइड के साथ प्रतिबिंब के माध्यम से एक विधि का आह्वान

मैं के बराबर प्रदर्शन करने के लिए कोशिश कर रहा हूँ: GetMethod का उपयोग

Container.RegisterType<IMyDataProvider, MockData.MockProvider>("MockData", new ContainerControlledLifetimeManager()) 

() पूरी तरह विफल हो गया था, इसलिए मैं इस बदसूरत बात कर समाप्त हो गया:

 MethodInfo registerTypeGeneric = Container.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance). 
     Where(p => p.ToString() == "Microsoft.Practices.Unity.IUnityContainer RegisterType[TFrom,TTo](System.String, Microsoft.Practices.Unity.LifetimeManager, Microsoft.Practices.Unity.InjectionMember[])").FirstOrDefault(); 
    MethodInfo registerTypeSpecific = registerTypeGeneric.MakeGenericMethod(new Type[] { typeof(IMyDataProvider), Assembly.LoadFrom("MockData.dll").GetType("MockData.MockProvider") }); 
    registerTypeSpecific.Invoke(Container, new object[] { "MockData", new ContainerControlledLifetimeManager() }); 

और यह खूबसूरती से काम करता है , जब तक कि शिकायत न हो, तब तक शिकायत करें क्योंकि मेरे पास इंजेक्शनमेन पैरामीटर नहीं हैं (वे वैकल्पिक हैं और मेरे पास देने के लिए कोई नहीं है)। इसलिए, दस्तावेज़ीकरण के अनुसार, मुझे वैकल्पिक पैरामीटर के साथ एक विधि कॉल करने के लिए Type.InvokeMember() का उपयोग करना होगा।

 Binder binder = new BootstrapperBinder(); 
    Container.GetType().InvokeMember("RegisterType", 
     BindingFlags.Instance | BindingFlags.Public | BindingFlags.OptionalParamBinding | BindingFlags.InvokeMethod, 
     binder, 
     Container, 
     new object[] { "MockData", new ContainerControlledLifetimeManager() }); 

मेरे BoostrapperBinder वर्ग करता है:

तो मैं ऐसा किया

public override MethodBase BindToMethod(BindingFlags bindingAttr, MethodBase[] match, ref object[] args, ParameterModifier[] modifiers, System.Globalization.CultureInfo culture, string[] names, out object state) 
    { 
    Type mockProvider = Assembly.LoadFrom("MockData.dll").GetType("MockData.MockProvider"); 
    state = new object(); 
    MethodInfo mi = Container.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance). 
     Where(p => p.ToString() == "Microsoft.Practices.Unity.IUnityContainer RegisterType[TFrom,TTo](System.String, Microsoft.Practices.Unity.LifetimeManager, Microsoft.Practices.Unity.InjectionMember[])").FirstOrDefault(); 
    return mi.MakeGenericMethod(new Type[] { typeof(ICarrierApprovalDataChangeAccessorEndPoint), mockProvider }); 
    } 

हाँ, यह बदसूरत है, लेकिन मैं तो बस, इस oen मामले के लिए इसका इस्तेमाल करते हैं तो यह काम करता है।

अब, समस्या यह है कि यह अभी भी तीसरे पैरामीटर की कमी के बारे में शिकायत कर रहा है। मैं शून्य या गुम नहीं कर सकता। या तो वाल्व, या यह croaks। मैंने बाध्यकारीफ्लैग के साथ और बिना कोशिश की है। ऑप्शनल पैराम बाइंडिंग। मैं उलझन में हूं।

उत्तर

1

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

registerTypeSpecific.Invoke(Container, new object[] { "MockData", new ContainerControlledLifetimeManager(), new InjectionMember[0] }); 

जेसन के लिए धन्यवाद:

समाधान पारित करने के लिए गया था "[0] नई InjectionMember" शून्य के बजाय, इसलिए आह्वान() इस तरह देखा जाना चाहिए था। उनके नमूने ने मुझे उस रास्ते को भेजा जिसने अंततः जवाब का नेतृत्व किया।

1

मैं null या Missing.Value पारित नहीं हो सकता या तो (कोड में Container.RegisterType उदाहरण डाल करने के लिए संपादित), या यह croaks।

क्रोक कैसे करें? आप जब आप एक विधि M() के माध्यम से M(params object[] objects) है जैसे कि यह मामला है कि objects विधि के भीतर रिक्त है हो जाएगा आह्वान एक params पैरामीटर के लिए null पारित करने में सक्षम होना चाहिए (।

दूसरे, आप अधिक सफाई से विधि देखने के कर सकते हैं। मैं अपनी उंगलियों पर एक संकलक नहीं है, लेकिन इस प्रयास करें:

var registerTypeMethodInfo = 
    typeof(IUnityContainer).GetMethods() 
          .Where(m => m.Name == "RegisterType") 
          .Where(m => m.GetParameters() 
           .Select(p => p.ParameterType) 
           .SequenceEqual(new[] { 
             typeof(string), 
             typeof(LifetimeManager), 
             typeof(InjectionMember[]) 
           }) 
          ) 
          .Where(m => m.GetGenericArguments().Count() == 2) 
          .SingleOrDefault(); 
Assert.NotNull(registerTypeMethodInfo); 
var methodInfo = 
    registerTypeMethodInfo.MakeGenericMethod(new[] { 
     typeof(IMyDataProvider), 
     typeof(MockData.MockProvider) 
    }); 

फिर तो जैसे विधि आह्वान, params InjectionMember[] पैरामीटर के लिए null गुजर:

methodInfo.Invoke(
    Container, 
    new object[] { 
     "MockData", 
     new ContainerControlledLifetimeManager(), 
     null 
    } 
); 

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

namespace ParamsTest { 
    interface Foo { 
     void M<T>(string s, int n, params object[] objects); 
    } 
    class Bar : Foo { 
     public void M<T>(string s, int n, params object[] objects) { 
      Console.WriteLine(s); 
      Console.WriteLine(n); 
      Console.WriteLine(objects == null); 
      Console.WriteLine(typeof(T).Name); 
     } 
    } 
    internal class Program { 
     internal static void Main(string[] args) { 
      var genericMethodInfo = 
       typeof(Foo).GetMethods() 
        .Where(m => m.Name == "M") 
        .Where(m => m.GetParameters() 
         .Select(p => p.ParameterType) 
         .SequenceEqual(new[] { 
          typeof(string), 
          typeof(int), 
          typeof(object[]) 
         }) 
        ) 
        .Where(m => m.GetGenericArguments().Count() == 1) 
        .SingleOrDefault(); 
      var methodInfo = 
       genericMethodInfo.MakeGenericMethod(
        new[] { typeof(DateTime) } 
       ); 
      var bar = new Bar(); 
      methodInfo.Invoke(bar, new object[] { "Hello, world!", 17, null }); 
     } 
    } 
} 

यह प्रिंट:

Hello, world! 
17 
True 
DateTime 

कंसोल पर

यहाँ एक आत्म निहित उदाहरण है कि काम करता है।

मैंने बाध्यकारीफ्लैग के साथ और बिना प्रयास किए हैं। ऑप्शनल पैराम बाइंडिंग।मैं उलझन में हूं।

params किसी विधि के हस्ताक्षर का हिस्सा नहीं है। यह परिवर्तनीय-लंबाई पैरामीटर सूचियों को अनुमति देने के लिए एक कंपाइलर चाल है। BindingFlags.OptionalParamBinding वैकल्पिक मानकों को उनके डिफ़ॉल्ट मानों को बाध्य करने के लिए है।

+0

GetMethods में LINQ एक से अधिक रिटर्न के कारण विफल रहता है (इसमें 16 ओवरराइड हैं, उनमें से कुछ अलग जेनेरिक प्रकार पैरामीटर के साथ हैं), लेकिन अगर मैं methodinfo प्राप्त करने के लिए अपना रास्ता उपयोग करता हूं, तो Invoke अभी भी शून्य के साथ विफल रहता है RegisterType() विधि में संदर्भ अपवाद। चूंकि कंटेनर शून्य नहीं है, इसलिए मैं केवल अनुमान लगा सकता हूं कि शून्य पैरामीटर कारण है। – Pete

+0

यह ठीक करना आसान है। 'सिंगलऑर्डफॉल्ट' पर कॉल करने से पहले '। जहां (m => m.GetGenericArguments()। गणना() == 2)' जोड़ें। – jason

+0

समस्या के लिए आप 'शून्य' के साथ अनुभव कर रहे हैं, एक स्थिर विधि आमंत्रण के माध्यम से विधि का आह्वान करने का प्रयास करें (यानी, प्रतिबिंब को हटा दें)। बस 'कंटेनर। रजिस्ट्रार टाइप करें ("MockData", नया कंटेनर नियंत्रित नहीं लाइफटाइम मैनेजर(), शून्य)' और देखें कि आपको एक ही समस्या है या नहीं। यदि आप करते हैं, तो समस्या गतिशील आमंत्रण नहीं है और इसके बजाय यह कुछ और है (शायद जिस तरह से आप कंटेनर सेट करते हैं?)। – jason

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