標籤:
跨越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);
}
}
}
《CLR via C#》 第22章 CLR寄宿和AppDomain 跨越AppDomain邊界訪問對象