.NET Core WPF运行时跨AppDomain注入类型及动态替换可行吗?
.NET Core WPF中跨隔离上下文加载同名类型并动态替换的实现
问题描述
能否在.NET Core WPF应用运行的任意阶段,将包含MyType类型的程序集加载到独立的隔离上下文(原AppDomain替代方案)并在主上下文使用?之后能否销毁该隔离上下文,加载另一个同样包含MyType类型的程序集并在主域中使用?
目标是无需重启应用、不使用dynamic对象以避免装箱/拆箱,实现Value的多种类型适配。
示例代码结构:
// 主上下文代码 var list = new List<IMyType>(); // 使用共享接口统一处理 // 第一个隔离上下文加载的程序集中的类型 public class MyType : IMyType { public string Value { get; set; } object IMyType.Value => Value; } // 第二个隔离上下文加载的程序集中的类型 public class MyType : IMyType { public int Value { get; set; } object IMyType.Value => Value; }
核心结论与实现方案
1. .NET Core中AppDomain的现状
.NET Core及后续版本(.NET 5+)已彻底移除AppDomain的隔离与卸载能力,官方推荐使用AssemblyLoadContext(简称ALC)作为程序集隔离加载、卸载的替代方案,因此无法通过传统AppDomain方式实现需求,必须切换到ALC方案。
2. 具体实现步骤
(1)定义共享接口
在主应用和所有待加载的程序集之间共享一个统一接口,让主上下文能通过接口访问不同版本MyType的Value成员,完全避免dynamic:
// 放在主应用、所有插件程序集都能引用的独立类库中 public interface IMyType { object Value { get; } // 也可按需添加强类型方法,比如: // T GetValue<T>(); }
(2)用AssemblyLoadContext加载程序集
创建可回收的ALC实例加载目标程序集,通过反射创建MyType实例并转换为IMyType接口:
// 加载第一个程序集 var alc1 = new AssemblyLoadContext("MyTypeAssembly1", isCollectible: true); var assembly1 = alc1.LoadFromAssemblyPath(@"path\to\first\MyTypeAssembly.dll"); var myType1 = (IMyType)Activator.CreateInstance(assembly1.GetType("MyType")); list.Add(myType1); // 访问Value string stringValue = (string)myType1.Value;
(3)卸载隔离上下文并加载新程序集
切换程序集前,必须释放所有对当前ALC中对象的引用,再调用Unload()卸载ALC,最后创建新ALC加载第二个程序集:
// 释放对第一个ALC中对象的所有引用 list.Remove(myType1); myType1 = null; // 卸载第一个ALC alc1.Unload(); // 加载第二个程序集 var alc2 = new AssemblyLoadContext("MyTypeAssembly2", isCollectible: true); var assembly2 = alc2.LoadFromAssemblyPath(@"path\to\second\MyTypeAssembly.dll"); var myType2 = (IMyType)Activator.CreateInstance(assembly2.GetType("MyType")); list.Add(myType2); // 访问Value int intValue = (int)myType2.Value;
3. 关键注意事项
- 必须创建可回收ALC:初始化时需设置
isCollectible: true,否则该ALC无法被卸载。 - 彻底释放引用:卸载ALC前,主上下文不能保留任何来自该ALC的对象引用,否则GC无法回收资源,ALC也无法真正卸载。
- 接口版本一致性:所有加载的程序集必须引用同一个接口类库,确保主上下文与隔离上下文的
IMyType是同一类型,否则类型转换会失败。 - 避免直接引用MyType:主上下文不能直接引用
MyType类型,只能通过IMyType接口交互,否则目标程序集会被加载到主ALC中,无法卸载。
内容的提问来源于stack exchange,提问作者Boppity Bop
相关产品推荐
相关产品推荐

