我正在寻找一种方法来隔离可以卸载的单独AppDomain中的组件(基于第三方dll)。我的计划是使用基于CreateInstanceAndUnwrap
和MarshalByRefObject
的对象与组件进行通信。
问题是,为了在主程序集中使用从MarshalByRefObject
派生的对象,它必须引用组件dll,我试图避免这种情况。我以为我可以通过界面解耦它
class MyObject: MarshalByRefObject, IMyObject
{
}
但是我无法将从CreateInstanceAndUnwrap
返回的对象强制转换为IMyObject
(因为它实际上是代理,而不是真正的对象?)。
我错过了什么,或者这是不能完成的,唯一的答案是WCF?
更新: 我遇到的实际问题是IMyObject被定义了两次:我将文件包含在主程序集和组件程序集中。这样我得到一个异常“无法将透明代理强制转换为类型”。当我只使用我从两个程序集引用的一个接口/类定义时,它工作正常(无论是建议还是如上所述)。
答案 0 :(得分:2)
呃,无论如何,界面有点糟糕。
抛弃它并使用继承自MBRO的抽象基类。
public abstract class MyObject : MarshalByRefObject
{
protected MyObject() : base() {}
public abstract void LoadPluginAssemblyLol();
public abstract void ExecuteSuperCollider();
}
将其拉回边界并以此方式控制插件。此外,请记住不要在类型上公开事件(事件订阅者在没有意识到的情况下被跨越边界)并且您应该只接受方法参数并且返回值是基元或严格控制,以便您不会意外地结束在您的主域中加载的DLL。
您将遇到的另一个问题是,您必须通过 ISponsor 实施来管理代理的生命周期。否则,主机域中的实例将在10分钟后收集。
至于使用MyObject,你会......
//假设一个实现,例如'class MyObjectImplementation:MyObject {...}'
var type = typeof(MyObjectImplementation);
var newDomain = CreateNewAppDomainKthx();
var controller = newDomain
.CreateInstanceAndUnwrap(
type.Assembly.FullName,
type.FullName) as MyObjectImplementation;
controller.LoadPluginAssemblyLol();
controller.ExecuteSuperCollider();