CLR via C# 读书笔记 6-2 不同AppDomain之间的通信 z
跨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
{
publicclass Program
{
staticvoid 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 的方式跨域通信
publicsealedclass MarshalByRefType : MarshalByRefObject
{
public MarshalByRefType()
{
Console.WriteLine("{0} ctor running in {1}",
this.GetType().ToString(), Thread.GetDomain().FriendlyName);
}
publicvoid 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]
publicsealedclass 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);
}
publicoverride String ToString()
{
return m_creationTime.ToLongDateString();
}
} // 没有标记为 Serializable 的类型 不能用marshaled by value 的方式跨域通信
// [Serializable]
publicsealedclass NonMarshalableType : Object
{
public NonMarshalableType()
{
Console.WriteLine("Executing in "+ Thread.GetDomain().FriendlyName);
}
}
}
CLR via C# 读书笔记 6-2 不同AppDomain之间的通信 z的更多相关文章
- 10月9日Android学习笔记:活动与服务之间的通信
最近在照着<第一行代码>这本书来学安卓,顺便记下笔记.主要的内容是Android中服务的第二种启动方式,通过活动绑定服务来启动服务,实现活动与服务之间的通信. 一. 首先创建一个服务类 p ...
- CLR via C# 读书笔记---常量、字段、方法和参数
常量 常量是值从不变化的符号.定义常量符号时,它的值必须能在编译时确定.确定后,编译器将唱两只保存在程序集元数据中.使用const关键字声明常量.由于常量值从不变化,所以常量总是被视为类型定义的一部分 ...
- Clr Via C#读书笔记---I/O限制的异步操作
widows如何执行I/O操作 构造调用一个FileStream对象打开一个磁盘文件-----FileStream.Read方法从文件中读取数据(此时线程从托管代码转为本地/用户模式代码)- ...
- Clr Via C#读书笔记---计算限制的异步操作
线程池基础 1,线程的创建和销毁是一个昂贵的操作,线程调度以及上下文切换耗费时间和内存资源. 2,线程池是一个线程集合,供应你的用程序使用. 3,每个CLR有一个自己的线程池,线程池由CLR控制的所有 ...
- Clr Via C#读书笔记---CLR寄宿和应用程序域
#1 CLR寄宿: 开发CLR时,Microsoft实际是将他实现成包含在一个dll中的COM服务器.Microsoft为CLR定义了一个标准的COM接口,并为该接口和COM服务器分配了GUID.安装 ...
- Clr Via C#读书笔记---程序集的加载和反射
#1 加载程序集 Assembly.Load: public class Assembly { public static Assembly Load(AssemblyName assemblyRef ...
- Clr Via C#读书笔记---垃圾回收机制
#1 垃圾回收平台的基本工作原理: 访问一个资源所需的具体步骤: 1)调用IL指令newobj,为代表资源的类型分配内存.在C#中使用new操作符,编译器就会自动生成该指令.2)初始化内存,设置资源的 ...
- Clr Via C#读书笔记---线程基础
趣闻:我是一个线程:http://kb.cnblogs.com/page/542462/ 进程与线程 进程:应用程序的一个实例使用的资源的集合.每个进程都被赋予了一个虚拟地址空间. 线程:对CPU进行 ...
- CLR via C# 读书笔记-26.线程基础
前言 这俩个月没怎么写文章做记录分享,一直在忙项目上线的事情,但是学习这件事情,停下来就感觉难受,clr线程这章也是反复看了好多遍,书读百遍其义自见,今天我们来聊下线程基础 1.进程是什么,以及线程起 ...
随机推荐
- centos6.3安装openvpn客户端
centos6.3安装openvpn客户端 Centos 默认是没有提供Openvpn的,而且在yum 的源里面也没有openvpn ,如果想使用yum安装的话要首先安装EPEL这个东西.www.2c ...
- one makefile file
#gcc test.cpp -L. -Wl,-Bdynamic -ltestlib -Wl,-Bstatic -ltestlib -Wl,-Bdynamic #make clean; make ini ...
- mysql---union和左连接的两倒面试题
第一道: 思路:无非是将hid与gid与t表中的tname关联起来.实质上是三表关联(m,t,t) 先将hid与tname关联起来,运用左连接 再将结果集与t表中的tname关联起来,使得gid与tn ...
- 纯原生js移动端城市选择插件
接着上一篇纯js移动端日期选择插件,话说今天同事又来咨询省市县联动的效果在移动端中如何实现,还是老样子,百度上一搜,诶~又全是基于jquery.zepto的,更加可恨的是大多数都是PC版的,三个sel ...
- IOS中如何自定义web应用的图标
在iPhone/iPad等苹果移动设备上,可以把网站”添加至主屏幕”,添加时的图标可以在HTML中自定义设置图片. 可以使用apple-touch-icon和apple-touch-icon-prec ...
- JDBC链接
//1. MySQL(http://www.mysql.com)mm.mysql-2.0.2-bin.jar Connection con = null; Class.forName( " ...
- WPF学习笔记3——Layout之1
一.概述 了解XAML的基本之后,进入Layout的学习.Layout,即布局,可能需要用到几种不同的容器.每一种容器都有各自的逻辑.在用户界面的设计过程中,很多时候是在想办法使得界面更加吸引.实在. ...
- codeforces Codeforces Round #345 (Div. 1) C. Table Compression 排序+并查集
C. Table Compression Little Petya is now fond of data compression algorithms. He has already studied ...
- Java内存管理:深入Java内存区域
Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来. 概述: 对于从事C和C++程序开发的开发人员来说,在内存管理领域,他们既是拥有最高权力的皇帝 ...
- CODEVS 1004四子连棋
[题目描述 Description] 在一个4*4的棋盘上摆放了14颗棋子,其中有7颗白色棋子,7颗黑色棋子,有两个空白地带,任何一颗黑白棋子都可以向上下左右四个方向移动到相邻的空格,这叫行棋一步,黑 ...