2012-12-05 11 views
18

जब मैं गतिशील रूप से सी # में किसी ऑब्जेक्ट पर "क्लास-स्तरीय सदस्य" के अर्थ में नहीं, "संकलित समय पर निर्धारित" की भावना में स्थिर रूप से परिभाषित ("स्थिर रूप से" कॉल करना चाहता हूं, तो मैं उपयोग कर सकता हूं प्रतिबिंब है कि विधि के लिए एक संभाल पाने के लिए और इसे लागू करने की: DynamicObject प्रतिक्रिया से इनहेरिट द्वारागतिशील वस्तु पर गतिशील रूप से एक विधि कैसे कॉल कर सकता हूं?

typeof(Foo).GetMethod("Bar").Invoke(foo, new object[] { /* params */ }); 

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

तो विडंबना यह है कि, मुझे लगता है कि आप गतिशील रूप से एक dynamic वस्तु पर एक गतिशील पद्धति के रूप में आसानी से फोन नहीं कर सकते हैं के रूप में आप एक गैर dynamic वस्तु पर एक परिभाषित विधि कॉल कर सकते हैं।

मैंने सीधे TryInvokeMember पर कॉल करने पर विचार किया है, लेकिन पहला तर्क InvokeMemberBinder, एक सार वर्ग का उदाहरण होना चाहिए। मुझे लगता है कि अगर मुझे गतिशील वस्तु पर एक गतिशील विधि को कॉल करने के लिए कक्षा को कार्यान्वित करना है, तो मुझे कुछ गलत करना होगा।

मैं कैसे को उसके नाम से dynamic वस्तु पर एक विधि कॉल कर सकते हैं, यह जानते हुए कि लक्ष्य वर्ग इसे लागू नहीं करता है और उसे TryInvokeMember का उपयोग कर के लिए प्रतिक्रिया व्यक्त किया जाना चाहिए कि?

उत्तर

9

इसके बारे में जाने का एक तरीका यह है कि डायनामिक ऑब्जेक्ट्स पर विधि आमंत्रण के लिए सी # कंपाइलर आउटपुट क्या है। इसके लिए Microsoft.CSharp.RuntimeBinder नामस्थान में [EditorBrowsable(EditorBrowsableState.Never)] चिह्नित प्रकारों के समूह की आवश्यकता होती है, इसलिए वे इंटेलिसेंस में दिखाई नहीं देंगे। कहने की जरूरत नहीं है, यह एक समर्थित परिदृश्य की तरह प्रतीत नहीं होता है, इसलिए इसे अपने जोखिम पर उपयोग करें!

इस कोड को एक वर्ग DynamicObject से प्राप्त की एक आवृत्ति पर किसी भी तर्क के बिना गतिशील Bar प्रणाली को बुलाती है:

dynamic dynamicObject = new DerivedFromDynamicObject(); 
var callSiteBinder = Binder.InvokeMember(CSharpBinderFlags.None, "Bar", Enumerable.Empty<Type>(), typeof(Program), 
    new[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) }); 
var callSite = CallSite<Action<CallSite, object>>.Create(callSiteBinder); 
callSite.Target(callSite, dynamicObject); 

This ब्लॉग पोस्ट और this one कॉल साइटों और बाइंडरों के बारे में अधिक रक्तमय विवरण है।

+0

मजेदार लगता है। मैं यह देखने के लिए इंतजार करूंगा कि किसी के पास वास्तव में एक समर्थित समाधान है क्योंकि जब यह काम करना बंद कर देता है तो शायद मैं अब और नहीं रहूंगा। – zneak

+1

दूसरी ओर, चूंकि संकलक पहले से ही करता है, इसलिए काम करना बंद करना संभव नहीं है, क्योंकि यह आज बनाया गया 'गतिशील' का उपयोग करके किसी भी एप्लिकेशन को मार देगा। – zneak

+0

@zneak ठीक है, मुझे लगता है कि यह एक बहुत ही सुरक्षित शर्त है। यह आश्चर्य की बात है कि वे इतनी बड़ी लंबाई में गए कि यह सुनिश्चित किया जा सके कि प्रकार छिपाए गए हैं। – Trillian

14

मेरे पास एक ओपन सोर्स (अपाचे लाइसेंस) फ्रेमवर्क डायनामाइटी (न्यूजेट में उपलब्ध) है जो डायनामिक बाइंडर कोड को समाहित करता है, इसमें कॉल साइट्स को स्वचालित रूप से कैशिंग करना शामिल है। इसमें हर प्रकार के बाइंडर (गेटर्स, सेटर्स, इवेंट्स, इंडेक्सर्स, ऑपरेटर, रूपांतरण) के लिए सुविधा विधियां हैं, लेकिन विशेष रूप से आप InvokeMember चाहते हैं।

डायनामिक बाइंडर कोड वास्तव में कक्षाओं के सदस्यों को स्थिर रूप से परिभाषित (संकलित समय पर) कॉल करते समय प्रतिबिंब (amortized) से तेज़ी से चलता है।

Dynamic.InvokeMember(foo,"Bar",arg...); 
+0

यह बहुत अच्छा लग रहा है! – zneak

+0

मैन! महान नजेट! सही काम करता है! धन्यवाद! जवाब के रूप में चिह्नित किया जाना चाहिए! – CodeHacker

+0

ग्रेट पैकेज, काम पूरा हो गया है। – Andro

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