AppDomain.CurrentDomain 的“详解 + 实用指南”,重点覆盖属性、事件、方法、常见用法与注意事项,并结合 WPF 桌面场景。

一、定位

  • 类型:System.AppDomain
  • CurrentDomain:返回当前线程所在线程的应用程序域(默认域或你创建的自定义域)。
  • 作用:管理程序集加载/解析、异常/退出生命周期、域级数据存取与隔离。

二、核心事件(最常用)

  • ProcessExit:进程即将退出(调用 Application.Shutdown 或进程终止时)。适合做最终持久化、日志刷写、释放资源。
  • DomainUnload:当前 AppDomain 卸载时触发(默认域通常在进程退出时卸载)。
  • UnhandledException:当前域中未捕获异常。用于最后兜底日志,但不能保证可恢复。
  • FirstChanceException:异常首次被抛出时(即使后续被捕获),用于调试或细粒度日志。
  • AssemblyLoad:程序集已加载(通知)。
  • AssemblyResolve:解析失败时动态提供程序集(从自定义目录/嵌入资源加载)。
  • TypeResolve/ResourceResolve/ReflectionOnlyAssemblyResolve:类型/资源/仅反射加载解析失败时提供回退。

示例(注册/解绑):

// 注册
AppDomain.CurrentDomain.ProcessExit += OnProcessExit;
AppDomain.CurrentDomain.DomainUnload += OnDomainUnload;
AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;

// 建议在应用退出时解绑(防止静态事件泄漏,尽管进程退出会清理)
AppDomain.CurrentDomain.ProcessExit -= OnProcessExit;
AppDomain.CurrentDomain.DomainUnload -= OnDomainUnload;
AppDomain.CurrentDomain.UnhandledException -= OnUnhandledException;

void OnProcessExit(object sender, EventArgs e) { /* 刷盘、写日志 */ }
void OnDomainUnload(object sender, EventArgs e) { /* 释放域内资源 */ }
void OnUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
    var ex = e.ExceptionObject as Exception;
    // 记录致命异常;e.IsTerminating 表示是否即将终止
}

三、常用属性

  • BaseDirectory:探测程序集的基础目录(AppDomainSetup.ApplicationBase)。用于确定加载路径。
  • RelativeSearchPath:相对探测路径(私有路径,强名称程序集不会从这里加载)。
  • ShadowCopyFiles:是否启用影子复制(避免锁定文件)。
  • FriendlyName:域的友好名(默认域通常为可执行文件名)。
  • Id:域标识。
  • IsFullyTrusted:域是否完全信任(CAS 相关;.NET Framework 桌面应用通常为 true)。
  • MonitoringIsEnabled(4.5+):启用域级监控(需显式开启)。配套:
    • MonitoringTotalAllocatedMemorySize / MonitoringTotalProcessorTime:域内分配内存与处理器时间。
  • SetupInformation:AppDomainSetup(包含 ApplicationBase、ConfigurationFile、PrivateBinPath 等)。

示例读取:

var d = AppDomain.CurrentDomain;
string baseDir = d.BaseDirectory;
string relPath = d.RelativeSearchPath;
bool shadowCopy = d.ShadowCopyFiles == "true";
string name = d.FriendlyName;
bool trusted = d.IsFullyTrusted;

四、常用方法与数据存取

  • GetAssemblies():获取当前域已加载的程序集列表。
  • Load(AssemblyName)/Load(string):加载程序集(不建议随意使用 string 版本)。
  • CreateDomain(name, evidence, setup):创建新域(隔离执行;桌面应用较少用)。
  • ExecuteAssembly(path, args):在域中执行程序集入口点。
  • SetData/GetData(name, value):域级键值存储(跨线程共享,域内有效)。
  • DoCallBack(CrossAppDomainDelegate):在目标域执行委托(跨域场景)。
  • SetPrincipalPolicy / SetThreadPrincipal:设置域默认主体策略(安全/身份相关)。

示例(域级数据):

AppDomain.CurrentDomain.SetData("MyKey", "MyValue");
var v = AppDomain.CurrentDomain.GetData("MyKey") as string;

五、程序集解析(AssemblyResolve)典型用法

  • 目标:当 CLR 无法在既定探测路径找到程序集时,你可以提供加载逻辑(例如从自定义目录或嵌入资源解压再加载)。
  • 注意:仅在解析失败时触发;返回 Assembly 实例。避免死循环。

示例(简化):

AppDomain.CurrentDomain.AssemblyResolve += (s, args) =>
{
    var an = new System.Reflection.AssemblyName(args.Name);
    string path = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "libs", an.Name + ".dll");
    return System.IO.File.Exists(path) ? System.Reflection.Assembly.LoadFrom(path) : null;
};

六、与 WPF/桌面程序的搭配建议

  • 异常处理:
    • WPF 主线程 UI 异常:Application.Current.DispatcherUnhandledException(更适合更新 UI 或提示)。
    • 域级/后台线程异常兜底:AppDomain.CurrentDomain.UnhandledException(做最终日志与崩溃上报)。
  • 退出与资源回收:ProcessExit/DomainUnload 中做持久化(如用户设置、窗口位置)与遥测上报(注意不要做长耗时)。
  • 程序集解析:如你将插件/扩展放在子目录,用 AssemblyResolve 提供路径。
  • 性能监控(4.5+):可以在启动时开启 MonitoringIsEnabled 用于域级统计(开销小,但仍建议评估)。

七、限制与陷阱

  • UnhandledException 并非全能:
    • 无法处理 StackOverflowException、AccessViolation、OutOfMemory 等某些致命崩溃。
    • 事件触发后通常进程将终止(e.IsTerminating=true),不要尝试复杂恢复。
  • AssemblyResolve 仅在解析失败时触发,且返回错误会导致加载失败;避免在事件里做重型 IO 或网络。
  • 影子复制 ShadowCopyFiles 多用于 ASP.NET/服务端;桌面应用启用的价值有限。
  • 多域复杂度高:跨域对象需 MarshalByRefObject 或可序列化;WPF 桌面通常不建议引入多域架构。
  • FirstChanceException 量大:仅用于调试或诊断,生产环境慎用以免日志爆量。

结论

  • AppDomain.CurrentDomain 是桌面应用的“域级生命周期与解析/异常枢纽”。在 WPF 中,配合 DispatcherUnhandledException 处理 UI 异常,使用 ProcessExit/DomainUnload 做收尾,按需使用 AssemblyResolve 做插件加载,就能覆盖绝大多数应用级场景。

了解更多

AppDomain | Microsoft Learn

System.Windows.Controls 命名空间 | Microsoft Learn

控件库 - WPF .NET Framework | Microsoft Learn

WPF 介绍 | Microsoft Learn

使用 Visual Studio 创建新应用教程 - WPF .NET | Microsoft Learn

https://github.com/HeBianGu

HeBianGu的个人空间-HeBianGu个人主页-哔哩哔哩视频

GitHub - HeBianGu/WPF-Control: WPF轻量控件和皮肤库

GitHub - HeBianGu/WPF-ControlBase: Wpf封装的自定义控件资源库

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐