不使用子类化,如何在Application对象实例化时收到通知?
解决方案
方法1:拦截Application.Current的属性赋值
Application.Current的静态属性赋值是触发初始化逻辑的关键节点,我们可以通过反射替换该属性的setter方法,在原赋值逻辑执行后自动处理初始化队列。
实现代码
using System.Reflection; using System.Reflection.Emit; public static class ApplicationInitializer { static ApplicationInitializer() { HookCurrentPropertySetter(); } private static void HookCurrentPropertySetter() { // 获取Application.Current属性的元信息 var currentProperty = typeof(Application).GetProperty( nameof(Application.Current), BindingFlags.Public | BindingFlags.Static); if (currentProperty == null) return; // 获取原始setter方法 var originalSetter = currentProperty.GetSetMethod(nonPublic: true); if (originalSetter == null) return; // 构建自定义setter逻辑:先执行原赋值,再处理初始化队列 var hookedSetter = new DynamicMethod( "HookedApplicationCurrentSetter", returnType: typeof(void), parameterTypes: new[] { typeof(Application) }, owner: typeof(ApplicationInitializer).Module, skipVisibility: true); var ilGenerator = hookedSetter.GetILGenerator(); // 传递参数并调用原始setter ilGenerator.Emit(OpCodes.Ldarg_0); ilGenerator.Emit(OpCodes.Call, originalSetter); // 调用队列处理方法 ilGenerator.Emit(OpCodes.Call, typeof(Globals).GetMethod( nameof(Globals.ProcessAppInitQueue), BindingFlags.Public | BindingFlags.Static)); ilGenerator.Emit(OpCodes.Ret); // 替换原始setter为自定义逻辑 var setterField = typeof(PropertyInfo).GetField( "_setMethod", BindingFlags.NonPublic | BindingFlags.Instance); setterField?.SetValue(currentProperty, hookedSetter.CreateDelegate(originalSetter.GetType())); } } // 全局队列管理类 public static class Globals { public static Queue<Action<Application>> AppInitQueue { get; } = new(); public static void ProcessAppInitQueue() { var currentApp = Application.Current; if (currentApp == null) return; while (AppInitQueue.Count > 0) { AppInitQueue.Dequeue()(currentApp); } } }
模块初始化器调整
在ModuleInitializer中只需触发ApplicationInitializer的静态构造函数,确保拦截逻辑生效:
[ModuleInitializer] public static void InitModule() { // 触发拦截器初始化 _ = typeof(ApplicationInitializer); void AppRelatedInitialization(Application app) { // 你的应用初始化逻辑 } if (Application.Current != null) { AppRelatedInitialization(Application.Current); } else { Globals.AppInitQueue.Enqueue(AppRelatedInitialization); } }
方法2:监听Application类型实例化
通过AppDomain的类型加载事件,拦截Application的构造函数调用,在实例创建后自动处理队列。这种方法更贴近实例化的源头,但实现复杂度更高:
using System.Reflection; using System.Reflection.Emit; public static class ApplicationInitializer { static ApplicationInitializer() { AppDomain.CurrentDomain.TypeResolve += OnApplicationTypeResolve; } private static Assembly? OnApplicationTypeResolve(object? sender, ResolveEventArgs args) { if (!args.Name.StartsWith(typeof(Application).FullName)) return null; var appAssembly = typeof(Application).Assembly; // 获取Application的无参构造函数 var defaultCtor = typeof(Application).GetConstructor( BindingFlags.Public | BindingFlags.Instance, Type.EmptyTypes); if (defaultCtor == null) return appAssembly; // 构建拦截后的构造函数逻辑 var hookedCtor = new DynamicMethod( "HookedApplicationCtor", typeof(void), Type.EmptyTypes, typeof(Application).Module, skipVisibility: true); var ilGenerator = hookedCtor.GetILGenerator(); // 调用原始构造函数 ilGenerator.Emit(OpCodes.Call, defaultCtor); // 处理初始化队列 ilGenerator.Emit(OpCodes.Call, typeof(Globals).GetMethod( nameof(Globals.ProcessAppInitQueue), BindingFlags.Public | BindingFlags.Static)); ilGenerator.Emit(OpCodes.Ret); // 替换原始构造函数(注:该操作需要更高权限,部分环境可能受限) var ctorField = typeof(ConstructorInfo).GetField( "_methodBase", BindingFlags.NonPublic | BindingFlags.Instance); ctorField?.SetValue(defaultCtor, hookedCtor.CreateDelegate(defaultCtor.GetType())); AppDomain.CurrentDomain.TypeResolve -= OnApplicationTypeResolve; return appAssembly; } }
关键注意事项
- 方法1的属性拦截方案兼容性更好,适用于大多数.NET桌面框架(WPF、WinForms)
- 反射和动态方法操作需要足够的运行权限,沙箱环境下可能无法执行
- 确保拦截逻辑在
Application.Current赋值前完成初始化,避免错过触发时机
内容的提问来源于stack exchange,提问作者Mark A. Donohoe
相关产品推荐
相关产品推荐

