2010-03-22 18 views
11

मैं रनटाइम पर अज्ञात प्रकार के वर्ग के गुणों को पढ़ने/लिखने के लिए प्रतिनिधि बनाने की कोशिश कर रहा हूं।अज्ञात प्रकारों के साथ बनाएँ डिलीगेट

मैं एक सामान्य वर्ग Main<T> और एक तरीका है जिसके इस तरह दिखता है:

Delegate.CreateDelegate(typeof(Func<T, object>), get) 

जहां get संपत्ति है कि पढ़ा जाना चाहिए की एक MethodInfo है। समस्या यह है कि जब संपत्ति int लौटाती है (मुझे लगता है कि यह मूल्य प्रकारों के लिए होता है) उपरोक्त कोड ArgumentException फेंकता है क्योंकि विधि को बाध्य नहीं किया जा सकता है। स्ट्रिंग के मामले में यह अच्छी तरह से काम करता है।

समस्या को हल करने के लिए मैंने कोड बदल दिया ताकि संबंधित प्रतिनिधि प्रकार MakeGenericType का उपयोग करके उत्पन्न हो। तो अब कोड है:

Type func = typeof(Func<,>); 
Type generic = func.MakeGenericType(typeof(T), get.ReturnType); 
var result = Delegate.CreateDelegate(generic, get) 

समस्या अब है generic की बनाई प्रतिनिधि उदाहरण तो मैं DynamicInvoke जो शुद्ध प्रतिबिंब का उपयोग कर क्षेत्र को पढ़ने के लिए के रूप में के रूप में धीमी गति से किया जाएगा का उपयोग करना होगा।

तो मेरा सवाल यह है कि कोड का पहला स्निपेट मूल्य प्रकारों के साथ विफल रहता है। MSDN के अनुसार के रूप में यह कहा गया है कि

एक प्रतिनिधि की वापसी प्रकार एक विधि की वापसी प्रकार के साथ संगत है अगर विधि की वापसी प्रकार प्रतिनिधि की वापसी प्रकार से अधिक प्रतिबंधात्मक है यह काम करना चाहिए

और दूसरे स्निपेट में प्रतिनिधि को निष्पादित करने के लिए ताकि यह प्रतिबिंब से तेज़ हो।

धन्यवाद।

उत्तर

10

आपकी समस्या का समाधान करने का एक तरीका यहां है। एक सामान्य विधि बनाएं:

public static Func<T, object> MakeDelegate<U>(MethodInfo @get) 
{ 
    var f = (Func<T, U>)Delegate.CreateDelegate(typeof(Func<T, U>), @get); 
    return t => f(t); 
} 

इस तरह, सी # के संकलक आवश्यक मुक्केबाजी (यदि हो तो) डालने object को f(t) (प्रकार U का) कन्वर्ट करने के लिए का ख्याल रखता है। अब आप इस MakeDelegate विधि को U पर @get.ReturnType पर सेट करने के लिए प्रतिबिंब का उपयोग कर सकते हैं, और आप जो वापस प्राप्त करेंगे वह Func<T, object> होगा जिसे DynamicInvoke का उपयोग करने के लिए सहारा देने की आवश्यकता के बिना बुलाया जा सकता है।

+0

बहुत बहुत धन्यवाद, यह काम किया! – Giorgi

2

आप आमंत्रण विफल रहता है क्योंकि आपको ऑब्जेक्ट की आवश्यकता नहीं होती है (मान INT) - स्पष्ट रूप से Func<T, int>Func<T, Int> नहीं है - यह किसी भी vt जैसे डबल या बूल के साथ काम नहीं करेगा। या तो एक बॉक्सिंग इंट (या जो कुछ भी आपको मिल गया है) लौटाएं। या (शायद बेहतर) प्रतिबिंब उत्सर्जित एपीआई का उपयोग करें।

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

उम्मीद है कि यह मदद करता है। ल्यूक

+0

सभी मूल्य प्रकार ऑब्जेक्ट से प्राप्त होते हैं इसलिए मैंने सोचा कि यह काम करेगा। मुझे प्रतिबिंब उत्सर्जन के बारे में पता है लेकिन यह CreateDelegate – Giorgi

+0

की तुलना में अधिक जटिल है लेकिन कॉन्वर्सिस और contravariance मूल्य प्रकारों के साथ काम नहीं करता है। यह मूल्य प्रकार और मुक्केबाजी का पूरा उद्देश्य है। http://msdn.microsoft.com/en-us/magazine/cc163727.aspx क्योंकि कोई IMPLICIT रूपांतरण नहीं है और अधिक http://blogs.msdn.com/ericlippert/archive/2007/10/ 1 9/covariance-and-contravariance-in-c-part-three-member-group-conversion-variance.aspx – luckyluke

3

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

आप अपने कोड में वह ऑपोड प्राप्त कर सकते हैं, लेकिन आपको सिस्टम का उपयोग करना होगा। Reflection.Emit।

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

+1

तो आप का मतलब है कि स्निपेट दो में उत्पन्न प्रतिनिधि पर डायनामिक इनवोक का उपयोग करना तेज है या क्या मैं गलत हूं? वर्तमान में मैं गुण लिखने/पढ़ने के लिए SetValue/GetValue का उपयोग कर रहा हूं और इसे तेज़ी से बनाना चाहता था। – Giorgi

0

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

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