CLR via C# 读书笔记 6-2 不同AppDomain之间的通信
来源:互联网 发布:大数据与经济发展 编辑:程序博客网 时间:2024/05/20 04:15
原文:http://www.cnblogs.com/PurpleTide/archive/2011/01/06/1927643.html
跨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); } }}
- CLR via C# 读书笔记 6-2 不同AppDomain之间的通信
- CLR via C# 读书笔记2-6
- clr via c#读书笔记
- CLR via C#读书笔记
- 《CLR via C#:框架设计》读书笔记 - CLR寄宿和AppDomain
- 《CLR via C#》读书笔记-CLR寄宿与AppDomain
- CLR via C# 读书笔记 1-2 创建线程的成本
- CLR via C# 读书笔记1-6
- CLR via C# 读书笔记2-2
- CLR via C# 读书笔记1-2
- CLR via C# 读书笔记2-1
- CLR via C# 读书笔记2-3
- CLR via C# 读书笔记2-4
- CLR via C# 读书笔记2-4 追记
- CLR via C# 读书笔记2-5
- CLR via C# 读书笔记2-7
- CLR via C# 读书笔记目录
- CLR via C# 2
- 解决Python字符串显示u'...'的问题
- 虚函数
- shell-commands
- java中的占位符
- bzoj 1051简单tarjan
- CLR via C# 读书笔记 6-2 不同AppDomain之间的通信
- Prim & Kruskal Algorithm
- [bzoj2038][2009国家集训队]小Z的袜子(hose) 莫队算法
- 第七章 为什么巴比伦塔会失败
- shell-keys
- [leetcode]583. Delete Operation for Two Strings
- 我对servlet的理解
- TLC59731 LED 驱动芯片 C语言驱动程序
- 三张图片了解activity进出场动画