跨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的更多相关文章

  1. 10月9日Android学习笔记:活动与服务之间的通信

    最近在照着<第一行代码>这本书来学安卓,顺便记下笔记.主要的内容是Android中服务的第二种启动方式,通过活动绑定服务来启动服务,实现活动与服务之间的通信. 一. 首先创建一个服务类 p ...

  2. CLR via C# 读书笔记---常量、字段、方法和参数

    常量 常量是值从不变化的符号.定义常量符号时,它的值必须能在编译时确定.确定后,编译器将唱两只保存在程序集元数据中.使用const关键字声明常量.由于常量值从不变化,所以常量总是被视为类型定义的一部分 ...

  3. Clr Via C#读书笔记---I/O限制的异步操作

    widows如何执行I/O操作      构造调用一个FileStream对象打开一个磁盘文件-----FileStream.Read方法从文件中读取数据(此时线程从托管代码转为本地/用户模式代码)- ...

  4. Clr Via C#读书笔记---计算限制的异步操作

    线程池基础 1,线程的创建和销毁是一个昂贵的操作,线程调度以及上下文切换耗费时间和内存资源. 2,线程池是一个线程集合,供应你的用程序使用. 3,每个CLR有一个自己的线程池,线程池由CLR控制的所有 ...

  5. Clr Via C#读书笔记---CLR寄宿和应用程序域

    #1 CLR寄宿: 开发CLR时,Microsoft实际是将他实现成包含在一个dll中的COM服务器.Microsoft为CLR定义了一个标准的COM接口,并为该接口和COM服务器分配了GUID.安装 ...

  6. Clr Via C#读书笔记---程序集的加载和反射

    #1 加载程序集 Assembly.Load: public class Assembly { public static Assembly Load(AssemblyName assemblyRef ...

  7. Clr Via C#读书笔记---垃圾回收机制

    #1 垃圾回收平台的基本工作原理: 访问一个资源所需的具体步骤: 1)调用IL指令newobj,为代表资源的类型分配内存.在C#中使用new操作符,编译器就会自动生成该指令.2)初始化内存,设置资源的 ...

  8. Clr Via C#读书笔记---线程基础

    趣闻:我是一个线程:http://kb.cnblogs.com/page/542462/ 进程与线程 进程:应用程序的一个实例使用的资源的集合.每个进程都被赋予了一个虚拟地址空间. 线程:对CPU进行 ...

  9. CLR via C# 读书笔记-26.线程基础

    前言 这俩个月没怎么写文章做记录分享,一直在忙项目上线的事情,但是学习这件事情,停下来就感觉难受,clr线程这章也是反复看了好多遍,书读百遍其义自见,今天我们来聊下线程基础 1.进程是什么,以及线程起 ...

随机推荐

  1. Stable Matching 稳定匹配 婚姻算法 shapley 算法

    作者:jostree  转载请注明出处 http://www.cnblogs.com/jostree/p/4051286.html 稳定匹配问题:有N男N女,每个人对于异性都一个排名,先需要得到一种稳 ...

  2. linux 定时执行 cron指令

    linux 中的 cron 定时执行命令,先上例子:每间隙两分钟把 "Hello world"写到 /tmp/hello.txt crontab -e */2 * * * * ec ...

  3. Android开发系列之调用WebService

    我在学习Android开发过程中遇到的第一个疑问就是Android客户端是怎么跟服务器数据库进行交互的呢?这个问题是我当初初次接触Android时所困扰我的一个很大的问题,直到几年前的一天,我突然想到 ...

  4. IE专用CSS,最全的CSS hack方式一览

    http://blog.csdn.net/freshlover/article/details/12132801

  5. 修改Sublime Text 3 的侧边栏字体大小

    此文转载哈,忘了作者地址,还请见谅!! 首先需要确保安装了Package ControlPackage Control作为ST必备插件,这里就不多介绍了,没装的话,google一下,各种介绍以及安装教 ...

  6. RSA使用 常识

    1公钥加密,私钥解密  OK反过来, 私钥加密,公钥解密 也OK 2 使用RSA加密 对称算法的key ,用对称算法加密 消息.伙伴收到消息后,RSA解密出 对称算法的key,再用这个key去解密消息 ...

  7. java实现的JDBCTemplate工具

    1.DButil import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; impor ...

  8. Amazon Alexa 语音识别2 : 设置

    开发者建立的Skill的主要设置项目都在Skill的console内.需要填写的东西大致有以下几个: 1.Skill 名字.这个名字是用户用来唤醒你这个Skill的. 2.Intent Schema: ...

  9. 粗略阅读《Agile Software Development》后的感想

    大致配合翻译和词典阅读了一下这篇文章之后,我另外还查阅了维基百科.百度百科和MBA智库百科还有一些网络上的文章.对敏捷开发有了一个大致上的浅显的认识. 敏捷建模(Agile Modeling,AM)的 ...

  10. Codeforces Round #209 (Div. 2)

    A: 要么是两次要么4次,判断是否在边界: #include<cstdio> using namespace std; int main() { int n,m,x; ; scanf(&q ...