You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

不使用子类化,如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 10:06:24