《CLR via C#》 第22章 CLR寄宿和AppDomain 跨越AppDomain边界访问对象

跨越AppDomain边界访问对象

将书中的代码(3处)将“MarshalByRefType”修改为“typeof(MarshalByRefType).FullName”,即可得到书中的输出结果:

将:MarshalByRefType mbrt = (MarshalByRefType)ad2.CreateInstanceAndUnwrap(exeAssembly,“MarshalByRefType”);

修改为:MarshalByRefType mbrt = (MarshalByRefType)ad2.CreateInstanceAndUnwrap(exeAssembly, typeof(MarshalByRefType).FullName);

修改后的代码为:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Reflection;
using System.Runtime.Remoting;

namespace CLRAppDomain
{
public class Marshal
{
private static void Marshaling()
{
//获取AppDomain的一个引用(“调用线程”在该AppDomain中执行)
AppDomain adCallingThreadDomain = Thread.GetDomain();
//每个AppDomain都有一个友好字符串名称,获取这个名称并显示
string callingDomainName = adCallingThreadDomain.FriendlyName;
Console.WriteLine("Defalut AppDomain's friendly name={0}", callingDomainName);
//获取&显示我们的AppDomain中包含“Main”方法的程序集
string exeAssembly = Assembly.GetEntryAssembly().FullName;
Console.WriteLine("Main assembly={0}", exeAssembly);

//定义一个局部变量引用一个AppDomain
//*** Demo 1,使用Marshal-by-Reference进行跨AppDomain通信 ***
Console.WriteLine("{0}*** Demo #1", Environment.NewLine);
//新建一个AppDomain,安全性和配置匹配与当前的AppDomain
AppDomain ad2 = AppDomain.CreateDomain("AD #2", null, null);
//将我们的程序集加载到AppDomain中,构造一个对象,把它封送会我们的AppDomain
//实际上得到的是一个代理引用
MarshalByRefType mbrt = (MarshalByRefType)ad2.CreateInstanceAndUnwrap(exeAssembly, typeof(MarshalByRefType).FullName);
Console.WriteLine("Type={0}", mbrt.GetType());//这里CLR在类型上撒谎了,得到Type=AppDomainLib.MashalByRefType,其实并不是这样
//证明得到的是一个代理的引用
Console.WriteLine("Is Proxy={0}", RemotingServices.IsTransparentProxy(mbrt));
//看起来像是在MashalByRefType上调用了一个方法,实在不然
//我们是在代理类型上调用了一个方法,代理使线程切换至拥有对象
//的那个AppDomain
mbrt.SomeMehtod();
//卸载新的AppDomain
AppDomain.Unload(ad2);
//mbrt引用了一个无效的代理对象,代理对象引用了一个无效的AppDomain
try
{
mbrt.SomeMehtod();
}
catch (AppDomainUnloadedException)
{
Console.WriteLine("Fall Call");
}
//*** Demo 2,使用Marshal-by-Value进行跨AppDomain通信 ***
Console.WriteLine("{0}*** Demo #2", Environment.NewLine);

//新建一个AppDomain,安全性和配置匹配与当前的AppDomain
ad2 = AppDomain.CreateDomain("AD #2", null, null);
//将我们的程序集加载到AppDomain中,构造一个对象,把它封送会我们的AppDomain
//实际上得到的是一个代理引用
mbrt = (MarshalByRefType)ad2.CreateInstanceAndUnwrap(exeAssembly, typeof(MarshalByRefType).FullName);
//对象的方法返回所返回对象的一个副本
//返回的对象是按值(而非引用)封送
MarshalByValType mbv = mbrt.MethodWidthReturn();
//证明我们得到的不是对一个代理对象的引用
Console.WriteLine("Is Porxy={0}", RemotingServices.IsTransparentProxy(mbv));
//看起来像是在MarshalByValType上调用方法,事实确实如此
Console.WriteLine("Return Object create:{0}", mbv.ToString());
//卸载AppDomain
AppDomain.Unload(ad2);
//mbv引用有效的对象,卸载AppDomain没有影响
try
{
//我们是在对象上调用一个方法,所有不会抛出异常
Console.WriteLine("Return Object create:{0}", mbv.ToString());
}
catch (AppDomainUnloadedException)
{
Console.WriteLine("Fail Call");
}

//*** Demo 3 使用不可封送的类型进行AppDomain通信 ****
Console.WriteLine("{0}*** Demo #3", Environment.NewLine);
//新建一个AppDomain,安全性和配置匹配与当前的AppDomain
ad2 = AppDomain.CreateDomain("AD #2", null, null);
//将我们的程序集加载到AppDomain中,构造一个对象,把它封送会我们的AppDomain
//实际上得到的是一个代理引用
mbrt = (MarshalByRefType)ad2.CreateInstanceAndUnwrap(exeAssembly, typeof(MarshalByRefType).FullName);
//对象的方法返回一个不可封送的对象,抛出异常
NonMarshalableType nmt = mbrt.MethodArgAndReturn(callingDomainName);
//这里的代码永远执行不到。。。
}
public static void Main()
{
Marshaling();
}
}

// 该类的实例可跨越AppDomain的边界“按引用封送”
public sealed class MarshalByRefType : MarshalByRefObject
{
public MarshalByRefType()
{
Console.WriteLine("{0} .ctor running in {1}", this.GetType().Name, Thread.GetDomain().FriendlyName);
}
public void SomeMehtod()
{
Console.WriteLine("Executing is " + Thread.GetDomain().FriendlyName);
}
public MarshalByValType MethodWidthReturn()
{
Console.WriteLine("Executing is " + Thread.GetDomain().FriendlyName);
MarshalByValType t = new MarshalByValType();
return t;
}
public NonMarshalableType MethodArgAndReturn(string callingDomainName)
{
// 注意callingDomainName是可以序列化的
Console.WriteLine("Calling from {0} to {1} ", callingDomainName, Thread.GetDomain().FriendlyName);
NonMarshalableType t = new NonMarshalableType();
return t;
}
}

// 该类的实例可跨越AppDomain的边界“按值封送”
[Serializable]
public sealed class MarshalByValType : Object
{
private DateTime m_CreateTime = DateTime.Now;//注意DateTime是可序列化的
public MarshalByValType()
{
Console.WriteLine("{0} ctor running in {1},create on {2}", this.GetType().ToString(),
Thread.GetDomain().FriendlyName, m_CreateTime);
}
public override string ToString()
{
return m_CreateTime.ToLongDateString();
}
}

// 该类的实例不可跨越AppDomain进行封送
//[Serializable]
public sealed class NonMarshalableType : Object
{
public NonMarshalableType()
{
Console.WriteLine("Executing in {0}", Thread.GetDomain().FriendlyName);
}
}

}

原文地址:https://www.cnblogs.com/zhangtingzu/p/5484802.html