我正在尝试编写一个表达式树,它可以使用MethodInfo给出的方法订阅EventInfo给出的事件.表达式树应编译成Action< object,object>其中参数是事件源对象和订阅对象. EventInfo和MethodInfos保证兼容.
这是我到目前为止:
// Given the following object Source = /**/; // the object that will fire an event EventInfo SourceEvent = /**/; // the event that will be fired object Target = /**/; // the object that will subscribe to the event MethodInfo Targetmethod = /**/; // the method that will react to the event // setting up objects involved var sourceParam = Expression.Parameter(typeof(object),"source"); var targetParam = Expression.Parameter(typeof(object),"target"); var sourceParamCast = Expression.Convert(sourceParam,SourceEvent.DeclaringType); var targetParamCast = Expression.Convert(targetParam,Targetmethod.DeclaringType); // Get subscribing method group. This is where things fail var targetmethodRef = Expression.MakeMemberAccess(targetParamCast,Targetmethod); // Subscribe to the event var addMethodCall = Expression.Call(sourceParamCast,SourceEvent.AddMethod,targetmethodRef); var lambda = Expression.Lambda<Action<object,object>>(addMethodCall,sourceParam,targetParam); var subscriptionAction = lambda.Compile(); // And then later,subscribe to the event subscriptionAction(Source,Target);
在调用MakeMemberAccess时,我得到以下异常:
ArgumentException: Member ‘void theMethodName()’ not field or property
解决方法
应该是这样.这里的复杂性是你必须使用CreateDelegate在lambda方法中创建一个委托.遗憾的是,似乎不可能在lambda方法中创建一个open委托(没有目标的委托),然后在执行lambda方法时在lambda方法中“关闭”它.或者至少我不知道该怎么做.可悲的是,CreateDelegate有点慢.
static Action<object,object> MakeFunc(EventInfo sourceEvent,MethodInfo targetmethod) { // setting up objects involved var sourceParam = Expression.Parameter(typeof(object),"source"); var targetParam = Expression.Parameter(typeof(object),"target"); var sourceParamCast = Expression.Convert(sourceParam,sourceEvent.DeclaringType); var targetParamCast = Expression.Convert(targetParam,targetmethod.DeclaringType); var createDelegate = typeof(Delegate).getmethod(nameof(Delegate.CreateDelegate),BindingFlags.Static | BindingFlags.Public,null,new[] { typeof(Type),typeof(object),typeof(MethodInfo) },null); // Create a delegate of type sourceEvent.EventHandlerType var createDelegateCall = Expression.Call(createDelegate,Expression.Constant(sourceEvent.EventHandlerType),targetParam,Expression.Constant(targetmethod)); // Cast the Delegate to its real type var delegateCast = Expression.Convert(createDelegateCall,sourceEvent.EventHandlerType); // Subscribe to the event var addMethodCall = Expression.Call(sourceParamCast,sourceEvent.AddMethod,delegateCast); var lambda = Expression.Lambda<Action<object,targetParam); var subscriptionAction = lambda.Compile(); return subscriptionAction; }
嗯……可以通过调用委托构造函数来完成.通过试用建立(没有找到很多关于此的文档):
static Action<object,targetmethod.DeclaringType); ConstructorInfo delegateContructror = sourceEvent.EventHandlerType.GetConstructor(BindingFlags.Instance | BindingFlags.Public,new[] { typeof(object),typeof(IntPtr) },null); IntPtr fp = targetmethod.MethodHandle.GetFunctionPointer(); // create the delegate var newDelegate = Expression.New(delegateContructror,Expression.Constant(fp)); // Subscribe to the event var addMethodCall = Expression.Call(sourceParamCast,newDelegate); var lambda = Expression.Lambda<Action<object,targetParam); var subscriptionAction = lambda.Compile(); return subscriptionAction; }
委托有一个带有两个参数的构造函数,即目标对象和IntPtr,它是该方法的本机函数指针.它通常由CIL用于ldftn / ldvirtftn,但.MethodHandle.GetFunctionPointer()是相同的“东西”.所以我们在我们构建的lambda表达式中调用这个构造函数.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。