zoukankan      html  css  js  c++  java
  • 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);
    }
    }
    }
  • 相关阅读:
    JavaSE-集合的遍历
    JavaSE-Collection常用方法
    JavaSE-异常
    JavaSE-匿名类_匿名内部类的使用
    JavaSE-内部类
    JavaSE-接口应用举例
    java线程的使用(Runnable)
    list根据所存对象属性排序
    Unable to locate appropriate constructor on class异常
    redis在java项目中的使用
  • 原文地址:https://www.cnblogs.com/zeroone/p/3621933.html
Copyright © 2011-2022 走看看