我一直在使用表达式树创建委托并订阅任何具有Action<Object[]>
的事件,其中所有事件参数都转换为对象数组。到目前为止,这一直很好,我需要订阅一个带有out/ref参数的事件,并且我需要设置这个参数的值。
有没有一种方法可以使用类似于表达式树的东西并订阅任何事件,但仍然能够为引发事件的对象设置/返回值?
创建委托的表达式树:
public static Delegate CreateProxyWithDynamicParameters(this EventInfo EventInfo, Action<object[]> Action)
{
var EventHandlerType = EventInfo.EventHandlerType;
var InvokeMethodInfo = EventHandlerType.GetMethod("Invoke");
var Parameters = InvokeMethodInfo.GetParameters().Select(Parameter => Expression.Parameter(Parameter.ParameterType, Parameter.Name)).ToArray();
var ConvertedParameters = Parameters.Select(Parameter => Expression.Convert(Parameter, typeof(object))).Cast<Expression>().ToArray();
var NewArrayInit = Expression.NewArrayInit(typeof(object), ConvertedParameters);
var Body = Expression.Call(Expression.Constant(Action), "Invoke", null, NewArrayInit);
var lambdaExpression = Expression.Lambda(Body, Parameters);
return Delegate.CreateDelegate(EventInfo.EventHandlerType, lambdaExpression.Compile(), InvokeMethodInfo.Name, ignoreCase: false);
}
代表订阅:
protected static void AddEvent<TMessage>(EventInfo eventInfo) where TMessage : EventArgs
{
void EventAction(object[] e)
{
// Run some event code.
}
var @delegate = eventInfo.CreateProxyWithDynamicParameters(EventAction);
DelegateDictionary[typeof(TMessage)] = @delegate;
eventInfo.AddEventHandler(x.Target, @delegate);
}
编辑:
这是香草简。需要设置HandlingCode
参数的位置。
InventorApplication.ApplicationEvents.OnSaveDocument += ApplicationEvents_OnSaveDocument;
private void ApplicationEvents_OnSaveDocument(_Document DocumentObject, EventTimingEnum BeforeOrAfter, NameValueMap Context, out HandlingCodeEnum HandlingCode)
{
HandlingCode = HandlingCodeEnum.kEventHandled;
}
使用Expression
将很难做到这一点,因为Expression
喜欢通过反射运行以进行回退,而不能通过反射处理refs。您可能可以通过原始IL进行,但是。。。这变得越来越混乱。
坦率地说,API事件让你的生活变得艰难。如果您控制API,我强烈建议使用更惯用的(object sender, SomeEventArgs args)
,其中SomeEventArgs : EventArgs
。然后,您的SomeEventArgs
将具有属性,用于您试图作为参数传递的所有内容,并且感兴趣的代码可以执行以下操作:
args.HandlingCode = ...
以分配值。