CLR via C# 读书笔记 6-2 不同AppDomain之间的通信

跨AppDomain通信有两种方式

  1.Marshal By reference : 传递引用

  2.Marshal By Value : 把需要传递的对象 通过序列化反序列化的方式传递过去(值拷贝)

    只有标记为 可序列化 Serializable 的类才能通过 Marshal By Value的方式通信

 

以下代码描述了几种跨域通信的情况

1.AppDomain是CLR的内部行为,windows完全不清楚有AppDomain的存在

2.在新的域中加载Assembly和Type最好用完整限定名(如果直接加载Type, CLR会自动加载Type所在的和所用到的Assembly)

3.默认情况下新建的应用程序域使用和当前域一样的权限设置,如果你需要手动指定权限,那么构造一个PermissionSet参数传给CreateDomain

4.同样的,如果想给应用程序设置不同的配置,构造一个AppDomainSetup传给他(可以设置配置文件,程序路径,影像拷贝什么的..)

5.跨域访问的时候不会发生线程的上下文切换

6.CreateInstanceAndUnwrap 默认调用对象的无参构造函数,当然,有些重载允许你调用有参构造函数

7.只有继承了System.MarshalByRefObject的对象才能以引用方式传递 (这是一个基类....c#又不允许多继承....还是挺麻烦的)

8.只有标记了了Serializable 的对象才能以值方式传递(内部的序列化反序列化) ,这里有比较严重的性能损耗

 

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

namespace TestConsole
{
public class Program
{
static void Main( string [] args)
{

// 获取一个指向应用程序域的引用
AppDomain adCallingThreadDomain = Thread.GetDomain();
// 每一个应用程序域都会被分配一个名字帮助调试 ,以下代码获取引用程序域的名字
String callingDomainName = adCallingThreadDomain.FriendlyName;
// 获取应用程序域的完整名
String exeAssembly = Assembly.GetEntryAssembly().FullName;
AppDomain ad2
= null ;

// ************************************************************************************************************
// 使用Marshal-by-Reference的方式跨域通信
Console.WriteLine( " {0}Demo #1 " , Environment.NewLine);
// 建立一个域,安全和配置均使用当前域的设置
ad2 = AppDomain.CreateDomain( " AD #2 " , null , null );
MarshalByRefType mbrt
= null ;
// 加载Assembly到新的域,new一个对象并且返回到当前域 (实际上返回的是一个引用代理)
mbrt = (MarshalByRefType)ad2.CreateInstanceAndUnwrap(exeAssembly, " TestConsole.MarshalByRefType " );
Console.WriteLine(
" Type={0} " , mbrt.GetType()); // CLR 对GetType做了一些手脚,返回的是被代理数据的真实类型
// 以下代码证明我们获取的是一个代理对象
Console.WriteLine( " Is proxy={0} " , RemotingServices.IsTransparentProxy(mbrt));
// 我们调用了代理类的SomeMethod() , 代理类跨域访问真正的对象
mbrt.SomeMethod();
// 卸载新建的那个应用程序域
AppDomain.Unload(ad2);
// mbrt refers to a valid proxy object; the proxy object refers to an invalid AppDomain
try
{
// 再次调用代理类的SomeMethod() , 由于域已经被卸载 抛出一个异常
mbrt.SomeMethod();
Console.WriteLine(
" Successful call. " );
}
catch (AppDomainUnloadedException)
{
Console.WriteLine(
" Failed call. " );
}

// ************************************************************************************************************
// 使用Marshal-by-Value 的方式跨域通信
Console.WriteLine( " {0}Demo #2 " , Environment.NewLine);
// 新建域
ad2 = AppDomain.CreateDomain( " AD #2 " , null , null );
// 加载程序集并创建代理类
mbrt = (MarshalByRefType)ad2.CreateInstanceAndUnwrap(exeAssembly, " TestConsole.MarshalByRefType " );
// 该方法返回了一个值的拷贝 marshaled by value (not be reference).
MarshalByValType mbvt = mbrt.MethodWithReturn();
// 证明返回值不是一个代理类
Console.WriteLine( " Is proxy={0} " , RemotingServices.IsTransparentProxy(mbvt));
// 查看返回值是谁创建的
Console.WriteLine( " Returned object created " + mbvt.ToString());
// 卸载应用程序域
AppDomain.Unload(ad2);
// 由于是值传递,那么卸载域对函数没有影响 // marshaled by value
try
{
// 不会有异常抛出
Console.WriteLine( " Returned object created " + mbvt.ToString());
Console.WriteLine(
" Successful call. " );
}
catch (AppDomainUnloadedException)
{
Console.WriteLine(
" Failed call. " );
}
// ************************************************************************************************************
// non-marshalable type 跨域通信
Console.WriteLine( " {0}Demo #3 " , Environment.NewLine);
ad2
= AppDomain.CreateDomain( " AD #2 " , null , null );
mbrt
= (MarshalByRefType)ad2.CreateInstanceAndUnwrap(exeAssembly, " TestConsole.MarshalByRefType " );
// 没有标记为 Serializable 的类型对象 不能通过marshaled by value 跨域通信
NonMarshalableType nmt = mbrt.MethodArgAndReturn(callingDomainName);

}
}

// 即使没有标记为Serializable 也可以通过 marshaled-by-reference 的方式跨域通信
public sealed class MarshalByRefType : MarshalByRefObject
{
public MarshalByRefType()
{
Console.WriteLine(
" {0} ctor running in {1} " ,
this .GetType().ToString(), Thread.GetDomain().FriendlyName);
}
public void SomeMethod()
{
Console.WriteLine(
" Executing in " + Thread.GetDomain().FriendlyName);
}
public MarshalByValType MethodWithReturn()
{
Console.WriteLine(
" Executing in " + Thread.GetDomain().FriendlyName);
MarshalByValType t
= new MarshalByValType();
return t;
}
public NonMarshalableType MethodArgAndReturn(String callingDomainName)
{
// NOTE: callingDomainName is [Serializable]
Console.WriteLine( " Calling from ‘{0}’ to ‘{1}’. " ,
callingDomainName, Thread.GetDomain().FriendlyName);
NonMarshalableType t
= new NonMarshalableType();
return t;
}
}

// 只有标记为 Serializable 的类型 才能用marshaled by value 的方式跨域通信
[Serializable]
public sealed class MarshalByValType : Object
{
private DateTime m_creationTime = DateTime.Now; // NOTE: DateTime is [Serializable]
public MarshalByValType()
{
Console.WriteLine(
" {0} ctor running in {1}, Created on {2:D} " ,
this .GetType().ToString(),
Thread.GetDomain().FriendlyName,
m_creationTime);
}
public override String ToString()
{
return m_creationTime.ToLongDateString();
}
}

// 没有标记为 Serializable 的类型 不能用marshaled by value 的方式跨域通信
// [Serializable]
public sealed class NonMarshalableType : Object
{
public NonMarshalableType()
{
Console.WriteLine(
" Executing in " + Thread.GetDomain().FriendlyName);
}
}
}

 

转载于:https://www.cnblogs.com/PurpleTide/archive/2011/01/06/1927643.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值