如何通过反射根据委托类型创建兼容的委托实例
问题描述
我正在构建适配WPF、UWP等多平台的.NET Standard通用类库,由于.NET Standard未收录大量平台专属类型,开发过程中常需要通过反射实现跨平台兼容逻辑。
近期我需要从Action类型委托创建UWP平台的DispatchedHandler实例:在UWP原生开发环境中可以直接通过new DispatchedHandler(action);的写法实现,但在.NET Standard环境下我只能获取到DispatchedHandler对应的Type对象,无法直接引用该类型。
我最初编写的实现代码如下:
private object GetDispatchedHandler(Action action) { // 省略前置逻辑 dispatchedHandlerType = windowsAssembly.GetType("Windows.UI.Core.DispatchedHandler"); // 需要将传入的action转换为DispatchedHandler实例返回 return Activator.CreateInstance(dispatchedHandlerType, action); }
上述代码运行时抛出异常:"Constructor on type 'Windows.UI.Core.DispatchedHandler' not found"。
我通过dispatchedHandlerType.GetConstructors()[0]获取到该类型唯一公开的构造函数,签名为{Void .ctor(System.Object, IntPtr)}。我推测第一个参数应当传入action对象,但不清楚第二个IntPtr类型的参数需要传入什么值,才能通过dispatchedHandlerConsructor.Invoke(new object[] { action, ??? });的方式正确创建DispatchedHandler实例。
原因说明
你获取到的(System.Object, IntPtr)签名构造函数是WinRT委托类型供运行时互操作层使用的内部构造函数,并非给用户代码直接调用的公开构造函数:第二个参数是指向原生函数指针的内部字段,手动传入任意值都无法正常工作,还可能引发内存访问违规。Activator.CreateInstance传入单个Action参数失败的核心原因是:WinRT委托类型和.NET托管委托属于两套不同的类型系统,反射查找构造函数时不会自动完成跨运行时的类型映射,因此无法匹配到接收托管委托的构造逻辑。
正确实现方式
不要直接调用构造函数创建实例,使用.NET框架自带的Delegate.CreateDelegate方法即可完成托管Action到WinRTDispatchedHandler的封送转换,代码如下:
private object GetDispatchedHandler(Action action) { // 省略前置获取dispatchedHandlerType的逻辑 var dispatchedHandlerType = windowsAssembly.GetType("Windows.UI.Core.DispatchedHandler"); // 自动处理跨运行时委托封送,生成可直接在UWP环境使用的DispatchedHandler实例 return Delegate.CreateDelegate(dispatchedHandlerType, action.Target, action.Method); }
实现说明:
DispatchedHandler本身是无参无返回值的委托类型,和Action的方法签名完全匹配,Delegate.CreateDelegate会自动处理WinRT与.NET托管层之间的封送逻辑,不需要手动处理函数指针、内存对齐等底层细节,生成的实例可以直接被UWP的CoreDispatcher等API正常调用。
如果需要做全平台兼容,可以在执行这段逻辑前先判断当前运行时是否加载了WinRT运行时程序集,非UWP环境下直接返回对应平台的调度委托实现即可,不要在非WinRT环境下强行创建DispatchedHandler实例。
内容的提问来源于stack exchange,提问作者EldHasp

