.Net Framework跨AppDomain引用非序列化对象可行吗?
解决方案:通过MarshalByRefObject代理间接访问原对象
你的核心问题在于试图跨AppDomain传递不可序列化的对象实例,这必然失败——即使包装在MarshalByRefObject类中,.NET仍会尝试序列化类的所有成员(包括那个不可序列化的ObjectIHaveNoControl实例)。
正确的思路是不传递原对象本身,而是传递一个可以远程调用的代理,让插件通过代理间接操作原对象(所有操作都会转发回原AppDomain执行),这和VSTO/Office Interop的跨进程代理逻辑完全一致。
具体实现步骤如下:
1. 定义共享接口
创建一个包含你需要操作原对象的所有方法/属性的接口,这个接口所在的程序集必须同时被原AppDomain和插件AppDomain引用:
public interface IObjectProxy { string GetTitle(); string GetId(); // 在这里添加你需要对原对象执行的其他操作,比如修改属性、调用方法等 }
2. 实现原AppDomain中的代理类
在原AppDomain中创建一个继承自MarshalByRefObject的代理类,它持有原对象的引用,并实现上面的接口:
public class ObjectProxy : MarshalByRefObject, IObjectProxy { private readonly ObjectIHaveNoControl _originalObj; public ObjectProxy(ObjectIHaveNoControl originalObj) { _originalObj = originalObj; } public string GetTitle() { return _originalObj.Title; } public string GetId() { return _originalObj.Id; } // 重写生命周期方法,避免代理过期 public override object InitializeLifetimeService() { return null; // 设置为无限生命周期,根据你的需求调整 } }
3. 修改插件的方法签名
让插件的方法接受IObjectProxy类型的参数,而不是原对象:
public class Addon { public void DoSomething(IObjectProxy objProxy) { // 版本1:显示Title MessageBox.Show(objProxy.GetTitle()); // 版本2:显示Id(切换插件版本时修改此处即可) // MessageBox.Show(objProxy.GetId()); } }
4. 传递代理对象给插件
在原AppDomain中创建代理实例,然后传递给插件——此时传递的是MarshalByRefObject的透明代理,而非原对象:
var proxy = Remote<Addon>.CreateProxy(addonDomain); // 在原AppDomain中创建代理类实例 var objProxy = new ObjectProxy(currentDomainObject); // 传递代理给插件,所有调用都会转发回原AppDomain proxy.RemoteObject.DoSomething(objProxy);
原理说明
MarshalByRefObject类型的实例跨AppDomain传递时,.NET不会序列化对象本身,而是创建一个透明代理返回给目标AppDomain。- 插件对代理的所有方法调用,都会通过.NET的远程调用机制转发回原AppDomain中的
ObjectProxy实例,再由它调用原对象的成员。 - 原对象始终留在它的原生AppDomain中,完全不需要序列化。
内容的提问来源于stack exchange,提问作者Jake
相关产品推荐
相关产品推荐

