2012-10-22 14 views
5

के वहाँ मान लेते हैं के लिए एक प्रतिनिधि बनाने के लिए कैसे एक तरीका है जिसके तर्क के परिवर्तनशील लेता हैतर्कों की चर संख्या के साथ एक लक्ष्य

Action<int, int> someAction += (a, b) => Target(a, b); 

वहाँ गतिशील इस लैम्ब्डा अभिव्यक्ति बनाने के लिए घटना के किसी भी प्रकार के हैंडलर संलग्न करने के लिए सक्षम होने के लिए एक संभावना है: एक लैम्ब्डा अभिव्यक्ति बनाने? कुछ की तरह:

someAction += CreateDelegate(typeof(someAction), Target); 

मैं Delegate.CreateDelegate का उपयोग करने की कोशिश की, लेकिन यह लक्ष्य तर्कों की ठोस सूची के साथ एक तरीका प्रदान करने की उम्मीद है। मुझे लगता है कि Expression.Lambda के साथ यह संभव होना चाहिए लेकिन अभी के लिए मुझे कोई सफलता नहीं मिली है। आप एक विचार है?

संपादित कार्रवाई और हैंडलर को

नाम बदलकर घटना को लक्षित करने के।

+1

घटनाक्रम निश्चित रूप से पता चलेगा कि वास्तव 2 पैरामीटर:

Expression<Action<int, int>> ex = (a, b) => Target(a, b); 

इस आधार पर मैं एक खुद प्रतिनिधि कारखाना बनाया प्रेषक और तर्क। –

+0

@ हेनक होल्टरमैन आईएनएचओ कार्यक्रम भी क्रियाएं हो सकती हैं। तर्क सीधे पास करना संभव है और आपको उन्हें EventArgs objec में पैक करने की आवश्यकता नहीं है। और आप प्रेषक ऑब्जेक्ट को हैंडलर में कितनी बार उपयोग करते हैं? –

उत्तर

3

मैं निम्न पंक्ति का विश्लेषण करके लैम्ब्डा के पीछे भाव पर एक दृष्टि डाली:

public static Delegate CreateDelegate(Type delegateType, Action<object[]> target) 
{ 
    var sourceParameters = delegateType.GetMethod("Invoke").GetParameters(); 

    var parameters = sourceParameters.Select(p => Expression.Parameter(p.ParameterType, p.Name)).ToArray(); 

    var castParameters = parameters.Select(p => Expression.TypeAs(p, typeof(object))).ToArray(); 

    var createArray = Expression.NewArrayInit(typeof(object), castParameters); 

    var invokeTarget = Expression.Invoke(Expression.Constant(target), createArray); 

    var lambdaExpression = Expression.Lambda(delegateType, invokeTarget, parameters); 

    return lambdaExpression.Compile(); 
} 
+1

यह बहुत अच्छा है! धन्यवाद। –

5

इस विधि के लिए एक प्रतिनिधि:

void Handle(params object[] args); 

, Action<object[]> होगा के रूप में प्रतिनिधियों params संशोधक का उपयोग नहीं कर सकते। आपको ऐसा करना होगा जो संकलक करता है, और ऑब्जेक्ट सरणी में अन्य विधि को मैप करें।

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

+3

काफी नहीं - 'एक्शन ' में 'पैरा' संशोधक नहीं है, इसलिए आप इसे 'एक्शन (फू, बार, बाज) के रूप में नहीं बुला सकते हैं, जबकि एक प्रतिनिधि जो * वास्तव में * उस हस्ताक्षर * होगा * उस तरह से कॉल करने योग्य। –

+0

आपकी त्वरित प्रतिक्रिया के लिए धन्यवाद! किसी अन्य कार्यवाही के लिए 'एक्शन ' मैप करने के लिए अभी भी समस्या है <-sethingething-> '। मुझे यह गतिशील रूप से करने की ज़रूरत है। शायद प्रतिबिंब के माध्यम से? –

+0

@ जोनस्केट मैंने अधिक स्पष्ट होने के लिए संपादित किया, लेकिन यह मेरा मुद्दा था - प्रतिनिधि 'पैरा' संशोधक का उपयोग नहीं कर सकते हैं, इसलिए ओपी को विधि कॉल को ऑब्जेक्ट सरणी में अपनी कॉलिंग विधि के भीतर लपेटना होगा। –

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