2012-03-22 20 views
6

anonymous methods का उपयोग करके आप सी # 2.0 के बाद से खाली प्रतिनिधि बना सकते हैं।अभिव्यक्ति पेड़ का उपयोग करके एक खाली प्रतिनिधि कैसे बनाएं?

public event EventHandler SomeEvent = delegate {}; 
public event Action OtherEvent = delegate {}; 

यह उदाहरण है useful to prevent having to do the null check when invoking events

Expression Trees का उपयोग करके मैं वही व्यवहार कैसे बना सकता हूं?

अब मुझे दिखाई देने वाला एकमात्र संभावित विकल्प Expression.Lambda() का उपयोग करना है, लेकिन जहां तक ​​मैं यह कह सकता हूं कि इसमें बहुत अधिक काम की आवश्यकता होगी।

उत्तर

2

जैसा कि यह पता चला है कि यह नहीं हैExpression.Lambda() का उपयोग करके बहुत अधिक काम करता है। हालांकि, मुझे अभी भी अन्य उत्तरों में रुचि है।

/// <summary> 
/// The name of the Invoke method of a Delegate. 
/// </summary> 
const string InvokeMethod = "Invoke"; 

/// <summary> 
/// Get method info for a specified delegate type. 
/// </summary> 
/// <param name = "delegateType">The delegate type to get info for.</param> 
/// <returns>The method info for the given delegate type.</returns> 
public static MethodInfo MethodInfoFromDelegateType(Type delegateType) 
{ 
    Contract.Requires(
     delegateType.IsSubclassOf(typeof(MulticastDelegate)), 
     "Given type should be a delegate."); 

    return delegateType.GetMethod(InvokeMethod); 
} 

जब आप EventInfo है के लिए यह इस प्रकार के रूप में आप एक खाली लैम्ब्डा बना सकते हैं::

EventInfo _event; 

... 

MethodInfo delegateInfo 
    = DelegateHelper.MethodInfoFromDelegateType(_event.EventHandlerType); 
ParameterExpression[] parameters = delegateInfo 
    .GetParameters() 
    .Select(p => Expression.Parameter(p.ParameterType)) 
    .ToArray(); 
Delegate emptyDelegate = Expression.Lambda(
    _event.EventHandlerType, 
    Expression.Empty(), "EmptyDelegate", true, parameters).Compile(); 
5

अपने उद्देश्य की प्रकृति से एक अभिव्यक्ति वृक्ष, हमेशा मूल डिजाइन में एक बयान के बजाय शरीर के लिए अभिव्यक्ति है।

सी # 3 में एक अभिव्यक्ति वृक्ष व्यक्त करने के लिए कोई रास्ता नहीं था जिसका शरीर खाली बयान ब्लॉक है। हाल ही में, अभिव्यक्ति वृक्ष पुस्तकालय को बयानों की अनुमति देने के लिए बढ़ा दिया गया है, लेकिन सी # अर्थपूर्ण विश्लेषण नियमों का लाभ उठाने के लिए अद्यतन नहीं किया गया था; आप अभी भी एक अभिव्यक्ति वृक्ष में एक कंबल lambda बारी नहीं कर सकते हैं।

+0

मुझे लगता है कि यही कारण है कि ['Expression.Empty'] (http://msdn.microsoft.com/en-us/library/dd294122.aspx) केवल सी # 4.0 से शुरू हो रहा है? मैं वास्तव में एक बयान को एक अभिव्यक्ति वृक्ष में बदलना नहीं चाहता था, बल्कि दूसरी तरफ। एक अभिव्यक्ति वृक्ष विवरण जिसके परिणामस्वरूप 'खाली' प्रतिनिधि होता है। मुझे लगता है कि मुझे [_a_ समाधान अब] मिला है (http://stackoverflow.com/a/9823691/590790), लेकिन मैं बस उलझन में हो सकता हूं। :) –

+2

@ स्टेवेनज्यूरिस: आह, मैंने आपके प्रश्न की जोर को गलत समझा। हां, आप एक अभिव्यक्ति वृक्ष "मैन्युअल" बना सकते हैं जो तार्किक रूप से एक खाली कथन ब्लॉक है। * सी # कंपाइलर * को आपके लिए लैम्ब्डा रूपांतरण के माध्यम से करने का कोई तरीका नहीं है, मेरा बिंदु था। –

1

विस्तार स्टीवन एक छोटे से जवाब देने के

मैं एक सहायक विधि है जो मैं पहले लिखा था की जरूरत किया बिट - मुझे एक्शन और फनक प्रकार दोनों के लिए एक खाली प्रतिनिधि बनाने के लिए समान कार्यक्षमता की आवश्यकता है - निम्नलिखित कार्य है जो मैंने उस कार्य के लिए बनाया है:

static class MethodInfoHelper<T> 
    { 
     static MethodInfoHelper() 
     { 
      VerifyTypeIsDelegate(); 
     } 

     public static void VerifyTypeIsDelegate() 
     { 
      //Lets make sure this is only ever used in code for Func<> types 
      if (!typeof(T).IsSubclassOf(typeof(Delegate))) 
      { 
       throw new InvalidOperationException(typeof(T).Name + " is not a delegate type"); 
      } 

      if (!typeof(T).Name.StartsWith("Func") && !typeof(T).Name.StartsWith("Action")) 
      { 
       throw new InvalidOperationException(typeof(T).Name + " is not a Func nor an Action"); 
      } 
     } 

     private static bool HasReturnType 
     { 
      get { return typeof(T).Name.StartsWith("Func"); } 
     } 

     /// <summary> 
     /// Creates an empty delegate of given type 
     /// </summary> 
     /// <typeparam name="T">Func or Action type to be created</typeparam> 
     /// <returns>A delegate to expression doing nothing</returns> 
     public static T CreateEmptyDelegate() 
     { 
      Type funcType = typeof(T); 
      Type[] genericArgs = funcType.GenericTypeArguments; 

      List<ParameterExpression> paramsExpressions = new List<ParameterExpression>(); 
      for (int paramIdx = 0; paramIdx < (HasReturnType ? genericArgs.Length - 1 : genericArgs.Length); paramIdx++) 
      { 
       Type argType = genericArgs[paramIdx]; 

       ParameterExpression argExpression = Expression.Parameter(argType, "arg" + paramIdx); 
       paramsExpressions.Add(argExpression); 
      } 

      Type returnType = HasReturnType ? genericArgs.Last() : typeof(void); 

      DefaultExpression emptyExpression = (DefaultExpression)typeof(DefaultExpression).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, 
       new Type[] { typeof(Type) }, null).Invoke(new[] { returnType }); 

      Expression<T> resultingExpression = Expression.Lambda<T>(
       emptyExpression, "EmptyDelegate", true, paramsExpressions); 

      return resultingExpression.Compile(); 
     } 
    } 
संबंधित मुद्दे