首页 > 解决方案 > 带 ref / out 参数的动态事件订阅

问题描述

我一直在使用表达式树来创建委托并使用 订阅任何事件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;
}

标签: c#

解决方案


你将很难做到这一点Expression,因为Expression喜欢能够通过反射运行事物以进行后备,并且它不能通过反射处理 refs。您也许可以通过原始 IL 来做到这一点,但是……这变得越来越混乱。

坦率地说,这个事件 API 让你很难过。如果您控制该 API,我强烈建议使用更惯用的(object sender, SomeEventArgs args)where SomeEventArgs : EventArgs。然后,您SomeEventArgs将拥有您尝试作为参数传递的所有内容的属性,并且感兴趣的代码可以执行以下操作:

args.HandlingCode = ...

分配一个值。


推荐阅读