.NET(C#): MarshalByRefObject的非静态方法和AppDomain.DoCallBack
首先,静态类型是对所有AppDomain可见且是只保存一份的,而如果在AppDomain.DoCallBack中使用了非静态方法调用,那么目标对象就必须被封送,几年前写过一篇文章:AppDomain.DoCallBack方法和Lambda表达式,就是讲的如果在DoCallBack方法中使用了捕获外部变量的Lambda表达式,那么由于编译器会把此类Lambda调用编译成生成类型的实例方法调用,所以会造成异常抛出(因为生成类型无法被封送)。也写过另一篇关于AppDomain中CreateInstance方法和对象的封送:多个AppDomain下有趣的封送对象。今天来简单看下AppDomain类型的DoCallBack方法回调对象方法的情况。
回调按引用封送的对象(即MarshalByRefObject)方法时,DoCallBack回调完全等效于直接调用代码,对象根本不会被封送,也不存在透明代理,如下代码:
class Program: MarshalByRefObject
{
//用来存储第一个Program对象
static Program FirstProgram;
static void Main()
{
var program = FirstProgram = new Program();
program.Doo();
}
//创建新的AppDomain
void Doo()
{
var domain = AppDomain.CreateDomain("另一个AppDomain");
domain.DoCallBack(Callback);
AppDomain.Unload(domain);
}
//AppDomain.DoCallBack回掉方法
void Callback()
{
Console.WriteLine("来自 {0}", AppDomain.CurrentDomain.FriendlyName);
Console.WriteLine("同一个对象:{0}", FirstProgram == this);
Console.WriteLine("是透明代理:{0}", System.Runtime.Remoting.RemotingServices.IsTransparentProxy(this));
}
}
输出:
来自 Mgen.exe
同一个对象:True
是透明代理:False
可以看到,方法在主AppDomain中执行。
而如果对象是按值封送的话,即可序列化的对象,DoCallBack会封送对象。
我们可以直接把上面的Program类型去掉继承自MarshalByRefObject类型,然后加上[Serializable]特性,这样他就可以按值封送了,如下:
[Serializable]
class Program
{
//和上面相同
}
再次运行,这次会输出:
来自 另一个AppDomain
同一个对象:False
是透明代理:False
OK,那么怎样解决MarshalByRefObject对象无法通过实例回调进行封送的问题呢?答案就是不通过实例方法,用静态方法作为DoCallBack参数,然后使用AppDomain的Get/SetData方法来传递也就是封送这个对象。
如下代码:
class Program: MarshalByRefObject
{
//用来存储第一个Program对象
static Program FirstProgram;
static void Main()
{
var program = FirstProgram = new Program();
program.Doo();
}
//创建新的AppDomain
void Doo()
{
var domain = AppDomain.CreateDomain("另一个AppDomain");
domain.SetData("TestData", this);
//使用静态的回调方法
domain.DoCallBack(StaticCallBack);
AppDomain.Unload(domain);
}
//静态回调方法
static void StaticCallBack()
{
var program = (Program)AppDomain.CurrentDomain.GetData("TestData");
Console.WriteLine("来自 {0}", AppDomain.CurrentDomain.FriendlyName);
Console.WriteLine("同一个对象:{0}", FirstProgram == program);
Console.WriteLine("是透明代理:{0}", System.Runtime.Remoting.RemotingServices.IsTransparentProxy(program));
}
}
输出:
来自 另一个AppDomain
同一个对象:False
是透明代理:True
对象被成功封送,同时透明代理判断返回True!
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。