我有一个相对动态的事件过程,我需要能够解释传递给动态处理程序的参数,但是我很难做到这一点。
请注意,以下代码是100%正常运行。它只需要调整以满足要求。
下面是一个定义Action和Event的简单类。 OnLeftClickEvent()方法接收args的object [],由于事件限制,必须将其封装在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 });
}
}
}
在Start()方法中,我定义了一个动态处理程序,在Update()中,它被触发并传递了所需的数据。
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();
}
}
答案 0 :(得分: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;
});
}
为了澄清,我只需要以正确的方式投射e [1]:((AppArgs)e [1])
我现在可以按照我需要的方式自由访问AppArgs的成员。 谢谢大家的帮助,非常感谢。