2013-06-22 18 views
1

我有一個相對動態的事件過程,我需要能夠解釋傳遞給動態處理程序的參數,但我遇到了麻煩。傳遞和解釋參數 - 動態處理程序

請注意,下面的代碼是100%的功能。它只是需要調整以滿足要求。

下面是一個簡單的類,它定義了一個Action和Event。 OnLeftClickEvent()方法接收由於事件約束而產生的args對象[],必須封裝在EventArgs中。

public class SomeSubscriber : SubscriberBase 
{ 
    private Logger<SomeSubscriber> debug = new Logger<SomeSubscriber>(); 

    public Action LeftClickAction; 
    public event EventHandler LeftClickEvent; 

    public SomeSubscriber() 
    { 
     LeftClickAction += OnLeftClickEvent; 
    } 

    public void OnLeftClickEvent(params object[] args) 
    { 
     AppArgs eventArgs = new AppArgs(this, args); 

     if(LeftClickEvent != null) LeftClickEvent(this, eventArgs); 
    } 
} 

在接收端是實現動態處理程序和觸發事件的類:

public class EventControllBase : _MonoControllerBase 
{ 
    private Logger<EventControllBase> debug = new Logger<EventControllBase>(); 

    SomeSubscriber subscriber; 

    private void Start() 
    { 
     subscriber = new SomeSubscriber(); 

     subscriber.AddHandler("LeftClickEvent", e => 
     { 
      debug.LogWarning(string.Format("Received {0} from {1} ", e[1], e[0])); 
      return true; 
     }); 
    } 

    private void Update() 
    { 
     if(Input.GetMouseButtonDown(0)) 
     { // Trigger events. 
      subscriber.InvokeDelegate("LeftClickAction", (object) new object[]{ this, Input.mousePosition }); 
     } 
    } 
} 

在我定義在更新(動態處理程序,並開始()方法)其被觸發並傳遞所需的數據。

e [1]顯然是EventArgs類型(AppArgs:EventArgs是特定的),但我不確定如何訪問成員以獲取實例中的數據。我嘗試過鑄造,但它是一個不行。

這裏是AppArgs的身體,如果有幫助:

public class AppArgs : EventArgs 
{ 
public object sender {get; private set;} 
private object[] _args; 

public AppArgs(object sender, object[] args) 
{ 
    this.sender = sender; 
    this._args = args; 
} 

public object[] args() 
{ 
    return this._args; 
} 
} 

動態處理器

public static class DynamicHandler 
{ 
     /// <summary> 
     /// Invokes a static delegate using supplied parameters. 
     /// </summary> 
     /// <param name="targetType">The type where the delegate belongs to.</param> 
     /// <param name="delegateName">The field name of the delegate.</param> 
     /// <param name="parameters">The parameters used to invoke the delegate.</param> 
     /// <returns>The return value of the invocation.</returns> 
     public static object InvokeDelegate(this Type targetType, string delegateName, params object[] parameters) 
     { 
      return ((Delegate)targetType.GetField(delegateName).GetValue(null)).DynamicInvoke(parameters); 
     } 

     /// <summary> 
     /// Invokes an instance delegate using supplied parameters. 
     /// </summary> 
     /// <param name="target">The object where the delegate belongs to.</param> 
     /// <param name="delegateName">The field name of the delegate.</param> 
     /// <param name="parameters">The parameters used to invoke the delegate.</param> 
     /// <returns>The return value of the invocation.</returns> 
     public static object InvokeDelegate(this object target, string delegateName, params object[] parameters) 
     { 
      return ((Delegate)target.GetType().GetField(delegateName).GetValue(target)).DynamicInvoke(parameters); 
     } 

     /// <summary> 
     /// Adds a dynamic handler for a static delegate. 
     /// </summary> 
     /// <param name="targetType">The type where the delegate belongs to.</param> 
     /// <param name="fieldName">The field name of the delegate.</param> 
     /// <param name="func">The function which will be invoked whenever the delegate is invoked.</param> 
     /// <returns>The return value of the invocation.</returns> 
     public static Type AddHandler(this Type targetType, string fieldName, 
      Func<object[], object> func) 
     { 
      return InternalAddHandler(targetType, fieldName, func, null, false); 
     } 

     /// <summary> 
     /// Adds a dynamic handler for an instance delegate. 
     /// </summary> 
     /// <param name="target">The object where the delegate belongs to.</param> 
     /// <param name="fieldName">The field name of the delegate.</param> 
     /// <param name="func">The function which will be invoked whenever the delegate is invoked.</param> 
     /// <returns>The return value of the invocation.</returns> 
     public static Type AddHandler(this object target, string fieldName, 
      Func<object[], object> func) 
     { 
      return InternalAddHandler(target.GetType(), fieldName, func, target, false); 
     } 

     /// <summary> 
     /// Assigns a dynamic handler for a static delegate or event. 
     /// </summary> 
     /// <param name="targetType">The type where the delegate or event belongs to.</param> 
     /// <param name="fieldName">The field name of the delegate or event.</param> 
     /// <param name="func">The function which will be invoked whenever the delegate or event is fired.</param> 
     /// <returns>The return value of the invocation.</returns> 
     public static Type AssignHandler(this Type targetType, string fieldName, 
      Func<object[], object> func) 
     { 
      return InternalAddHandler(targetType, fieldName, func, null, true); 
     } 

     /// <summary> 
     /// Assigns a dynamic handler for a static delegate or event. 
     /// </summary> 
     /// <param name="target">The object where the delegate or event belongs to.</param> 
     /// <param name="fieldName">The field name of the delegate or event.</param> 
     /// <param name="func">The function which will be invoked whenever the delegate or event is fired.</param> 
     /// <returns>The return value of the invocation.</returns> 
     public static Type AssignHandler(this object target, string fieldName, Func<object[], object> func) 
     { 
      return InternalAddHandler(target.GetType(), fieldName, func, target, true); 
     } 

     private static Type InternalAddHandler(Type targetType, string fieldName, 
      Func<object[], object> func, object target, bool assignHandler) 
     { 
      Type delegateType; 
      var bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | 
           (target == null ? BindingFlags.Static : BindingFlags.Instance); 
      var eventInfo = targetType.GetEvent(fieldName, bindingFlags); 
      if (eventInfo != null && assignHandler) 
       throw new ArgumentException("Event can be assigned. Use AddHandler() overloads instead."); 

      if (eventInfo != null) 
      { 
       delegateType = eventInfo.EventHandlerType; 
       var dynamicHandler = BuildDynamicHandler(delegateType, func); 
       eventInfo.GetAddMethod(true).Invoke(target, new Object[] { dynamicHandler }); 
      } 
      else 
      { 
       var fieldInfo = targetType.GetField(fieldName); 
                //,target == null ? BindingFlags.Static : BindingFlags.Instance); 
       delegateType = fieldInfo.FieldType; 
       var dynamicHandler = BuildDynamicHandler(delegateType, func); 
       var field = assignHandler ? null : target == null 
           ? (Delegate)fieldInfo.GetValue(null) 
           : (Delegate)fieldInfo.GetValue(target); 
       field = field == null 
          ? dynamicHandler 
          : Delegate.Combine(field, dynamicHandler); 
       if (target != null) 
        target.GetType().GetField(fieldName).SetValue(target, field); 
       else 
        targetType.GetField(fieldName).SetValue(null, field); 
        //(target ?? targetType).SetFieldValue(fieldName, field); 
      } 
      return delegateType; 
     } 

     /// <summary> 
     /// Dynamically generates code for a method whose can be used to handle a delegate of type 
     /// <paramref name="delegateType"/>. The generated method will forward the call to the 
     /// supplied <paramref name="func"/>. 
     /// </summary> 
     /// <param name="delegateType">The delegate type whose dynamic handler is to be built.</param> 
     /// <param name="func">The function which will be forwarded the call whenever the generated 
     /// handler is invoked.</param> 
     /// <returns></returns> 
     public static Delegate BuildDynamicHandler(this Type delegateType, Func<object[], object> func) 
     { 
      var invokeMethod = delegateType.GetMethod("Invoke"); 
      var parameters = invokeMethod.GetParameters().Select(parm => 
       Expression.Parameter(parm.ParameterType, parm.Name)).ToArray(); 
      var instance = func.Target == null ? null : Expression.Constant(func.Target); 
      var convertedParameters = parameters.Select(parm => Expression.Convert(parm, typeof(object))).Cast<Expression>().ToArray(); 
      var call = Expression.Call(instance, func.Method, Expression.NewArrayInit(typeof(object), convertedParameters)); 
      var body = invokeMethod.ReturnType == typeof(void) 
       ? (Expression)call 
       : Expression.Convert(call, invokeMethod.ReturnType); 
      var expr = Expression.Lambda(delegateType, body, parameters); 
      return expr.Compile(); 
     } 
    } 
+2

您的'Subscriber'類沒有'AddHandler'方法,所以此時此時不起作用。你可以使用'subscriber.LeftClickEvent + = ...' - 但說實話,根本不清楚爲什麼你有一個'Subscriber'類。它是什麼增加了.NET已經提供的代表和事件? –

+1

@Jon它可能從'SubscriberBase'繼承。 @Xerosigma你可以包含'AddHandler'的實現嗎? –

+0

@MikePrecup:啊,錯過了,是的。儘管如此,我仍然不清楚它的目的是什麼......看起來它正在重新發明輪子。 –

回答

0

所以我設法解決我的問題,下面都是我的代碼所做的修改以上:

首先,我對AppArgs做了一些細微的修改,這些修改很自我解釋:

public class AppArgs : EventArgs 
{ 
    public object sender {get; private set;} 
    public object[] args {get; private set;} 

    public AppArgs(object sender, object[] args) 
    { 
     this.sender = sender; 
     this.args = args; 
    } 
} 

下一步是找出如何正確投我EventArgs對象[]回到一個AppArgs:

EventControllBase.Start()

private void Start() 
    { 
     subscriber = new SomeSubscriber(); 

     subscriber.AddHandler("LeftClickEvent", e => 
     { 
      debug.LogWarning(string.Format("Received {0} from {1} ", ((AppArgs)e[1]).args[1], e[0])); 
      return true; 
     }); 
    } 

爲了澄清,我((AppArgs)e [1])

我現在可以以我需要的方式自由訪問AppArgs的成員了。 謝謝大家的幫助,非常感謝。