zoukankan      html  css  js  c++  java
  • C#程序集系列05,让程序集包含多个module

    本篇体验在一个程序集中包含多个module。

     

    □ 创建3个module

    →删除F盘as文件夹中的一些文件,只剩下如下3个文件
    27
    →用记事本打开MyFirstModule.cs文件,修改如下,并保存

    using System;
    
    public class MyFirstModule
    
    {
    
        public static void Hello()
    
        {
    
            Console.WriteLine("来自module 1的问候~");
    
        }
    
    }
    


    →用记事本打开MySecondModule.cs文件,修改如下,并保存

    using System;
    
    public class MySecondModule
    
    {
    
        public static void Hello()
    
        {
    
            Console.WriteLine("来自module 2的问候~");
    
        }
    
    }
    


    →把MyFirstModule.cs类编译成module
    28
    →把MySecondModule.cs类编译成module
    29
    →在F盘as文件夹中创建MyThirdModule.cs文件,用记事本打开编写如下代码,并保存

    using System;
    
    public class MyThirdModule
    
    {
    
        public static void Hello()
    
        {
    
            Console.WriteLine("来自module 3的问候~");
    
        }
    
    }
    


    →把MyThirdModule.cs类编译成module
    30

     

    □ 创建2个程序集并引用运行

    现在需要创建2个程序集,一个程序集中包含MyFirstModule和MySecondModule。另一个程序集包含MySecondModule和MyThirdModule。

    →创建程序集AssemblyA.dll包含MyFirstModule和MySecondModule。
    31
    →创建程序集AssemblyB.dll包含MySecondModule和MyThirdModule。
    32
    →编译MainClass.cs文件,引用AssemblyA.dll程序集
    33
    以上的dos命令等同于:csc /r:AssemblyA.dll /out:MainClass.exe MainClass.cs
    →运行MainClass.exe
    34
    →修改MainClass.cs文件

    using System;
    
    using System;
    
    class MainClass
    
    {
    
        static void Main()
    
        {
    
            MySecondModule.Hello();
    
            MyThirdModule.Hello();
    
        }
    
    }
    

    →编译MainClass.cs,引用AssemblyB.dll程序集
    35
    →运行MainClassAnother.exe
    36

     

    总结:一个程序集是可以包含多个module的。如果将不常用的代码放在单独的module中,就可以减少程序集的载入时间。如果通过网络下载程序集,还可以节约带宽。

     

      关于1楼stg609的问题


    问:上面代码中 module1 和 2 是什么时候加载到客户端的?

     

    我们来求证一下:

    →删除F盘as文件夹内的所有文件

    →在as文件夹下创建MyFirstModule.cs文件,修改如下,并保存

    using System;
    
    public class MyFirstModule
    
    {
    
    	public static void Hello()
    
    	{
    
    		Console.WriteLine("来自module1的问候~");
    
    	}
    
    }

    →在as文件夹下创建MySecondModule.cs文件,修改如下,并保存

    using System;
    
    public class MySecondModule
    
    {
    
    	public static void Hello()
    
    	{
    
    		Console.WriteLine("来自module2的问候~");
    
    	}
    
    }

    →把MyFirstModule.cs编译成module

    117

    →把MySecondModule.cs编译成module

    118

    →创建程序集,把MyFirstModule和MySecondModule包含其中

    119

    →在as文件夹下创建MainClass.cs文件,修改如下,并保存

    using System;
    
    class MainClass
    
    {
    
    	static void Main()
    
    	{
    
    		MyFirstModule.Hello();
    
    	}
    
    }

    其中只用到了一个module。

    →编译MainClass.cs文件,引用MyAssembly.dll文件

    120

    →运行MainClass.exe

    121

    →反编译MainClass.exe可执行文件,并输出到记事本查看IL代码

    122

    // Metadata version: v4.0.30319
    
    .assembly extern mscorlib
    
    {
    
      .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         // .zV.4..
    
      .ver 4:0:0:0
    
    }
    
    .assembly extern MyAssembly
    
    {
    
      .ver 0:0:0:0
    
    }
    
    .assembly MainClass
    
    {
    
      .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) 
    
      .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78   // ....T..WrapNonEx
    
                                                                                                                 63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 )       // ceptionThrows.
    
      .hash algorithm 0x00008004
    
      .ver 0:0:0:0
    
    }
    
    .module MainClass.exe
    
    // MVID: {7A00D175-6AB5-4EE8-BDDF-EEA3FC87EABD}
    
    .imagebase 0x00400000
    
    .file alignment 0x00000200
    
    .stackreserve 0x00100000
    
    .subsystem 0x0003       // WINDOWS_CUI
    
    .corflags 0x00000001    //  ILONLY
    
    // Image base: 0x003B0000
    
    // =============== CLASS MEMBERS DECLARATION ===================
    
    .class private auto ansi beforefieldinit MainClass
    
           extends [mscorlib]System.Object
    
    {
    
      .method private hidebysig static void  Main() cil managed
    
      {
    
        .entrypoint
    
        // 代码大小       8 (0x8)
    
        .maxstack  8
    
        IL_0000:  nop
    
        IL_0001:  call       void [MyAssembly]MyFirstModule::Hello()
    
        IL_0006:  nop
    
        IL_0007:  ret
    
      } // end of method MainClass::Main
    
      .method public hidebysig specialname rtspecialname 
    
              instance void  .ctor() cil managed
    
      {
    
        // 代码大小       7 (0x7)
    
        .maxstack  8
    
        IL_0000:  ldarg.0
    
        IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
    
        IL_0006:  ret
    
      } // end of method MainClass::.ctor
    
    } // end of class MainClass
    

    ○ .assembly extern MyAssembly,说明MainClass.exe引用了外部程序集MyAssembly.dll

    ○ void [MyAssembly]MyFirstModule::Hello(),说明MainClass.exe调用了MyAssembly程序集的Hello方法

    可是,依然无法看出2个module是否已经被加载到MyAssembly程序集中!

    →反编译MyAssembly.dll

    123

    // Metadata version: v4.0.30319
    
    .assembly extern mscorlib
    
    {
    
      .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         // .zV.4..
    
      .ver 4:0:0:0
    
    }
    
    .assembly MyAssembly
    
    {
    
      .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78   // ....T..WrapNonEx
    
                                                                                                                 63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 )       // ceptionThrows.
    
      .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) 
    
      .hash algorithm 0x00008004
    
      .ver 0:0:0:0
    
    }
    
    .file MyFirstModule.netmodule
    
        .hash = (ED 03 41 CA 3F 61 8C 1C FB 06 F2 05 8E 72 9B 86   // ..A.?a.......r..
    
                 AE 99 CA 28 )                                     // ...(
    
    .file MySecondModule.netmodule
    
        .hash = (B0 B3 96 5D C5 9D 56 C6 12 00 6E 03 DF 60 EA 9C   // ...]..V...n..`..
    
                 2F 87 A6 FE )                                     // /...
    
    .class extern public MyFirstModule
    
    {
    
      .file MyFirstModule.netmodule
    
      .class 0x02000002
    
    }
    
    .class extern public MySecondModule
    
    {
    
      .file MySecondModule.netmodule
    
      .class 0x02000002
    
    }
    
    .module MyAssembly.dll
    
    // MVID: {BBC0A811-A24C-4C47-8C24-5A7B96E114C8}
    
    .imagebase 0x10000000
    
    .file alignment 0x00000200
    
    .stackreserve 0x00100000
    
    .subsystem 0x0003       // WINDOWS_CUI
    
    .corflags 0x00000001    //  ILONLY
    
    // Image base: 0x003C0000

    ○  .module MyAssembly.dll,说明MyAssembly.dll中只有一个与程序集名称一致的一个module,FirstModule和SecondModule去哪了?

    ○ .file MyFirstModule.netmodule,原来FirstModule是作为MyAssembly.dll的外部文件存在的,即当程序集需要MyFirstModule的时候,再去加载。

    ○ .file MySecondModule.netmodule,SecondModule也是作为MyAssembly.dll的外部文件存在。

     

    至此,就可以回答stg609的问题了:

    当客户端调用程序集某个module的方法时,才去加载方法所在的module。因为module1和module2是以外部文件的形式存在于同一个程序集中的,当客户端调用module1的方法,module1才被加载。

     

    “C#程序集系列”包括:

      C#程序集系列01,用记事本编写C#,IL代码,用DOS命令编译程序集,运行程序

      C#程序集系列02,使用记事本查看可执行程序集的IL代码

      C#程序集系列03,引用多个module

      C#程序集系列04,在程序集包含多个module的场景下理解关键字internal

      C#程序集系列05,让程序集包含多个module

      C#程序集系列06,程序集清单,EXE和DLL的区别

      C#程序集系列07,篡改程序集

      C#程序集系列08,设置程序集版本

      C#程序集系列09,程序集签名

      C#程序集系列10,强名称程序集

      C#程序集系列11,全局程序集缓存

      C#程序集系列12,C#编译器和CLR如何找寻程序集

      C#程序集系列13,如何让CLR选择不同版本的程序集

    参考资料:

    http://www.computersciencevideos.org/  created by Jamie King

  • 相关阅读:
    python 并发编程 多进程 互斥锁 目录
    python 并发编程 多进程 互斥锁
    python 并发编程 多进程 守护进程
    python 并发编程 多进程 Process对象的其他属性方法 terminate与is_alive name pid 函数
    python 并发编程 多进程 Process对象的其他属性方法 join 方法
    python 并发编程 多进程 目录
    POJ 2253
    POJ 2255
    POJ 2250
    POJ 2248
  • 原文地址:https://www.cnblogs.com/darrenji/p/3968533.html
Copyright © 2011-2022 走看看