之程序集

作者:计算机知识
一、概述
  1. 先后集是.NET应用程序的安顿单元

    程序集是.NET应用程序的布署单元。
    程序集是本身描述的设置单元,由一个或多少个公文组成。
    常常扩张名是EXE或DLL的.NET可实行程序称为程序集。
    .NET程序集带有元数据。

  2. 次第集的特色

    • 先后集是自个儿描述的。
    • 本子的相互借重在先后集的清单中著录。
    • 程序集能够并行加载。
    • 应用程序使用应用程序域来确定保证其独立性。
    • 设置简便。
  3. 程序集的构造

    程序集由描述它的元数据、描述导出类型和形式的项目元数据、MSIL代码和财富整合。

  4. 程序集的清单
    程序集清单是元数据的一片段,描述了程序集和引用它所急需的具有音讯和依附关系。

    • 标记(名称、版本、文化和公钥)。
    • 属于该程序集的三个文本列表。
    • 引用程序集的列表。
    • 1组认同请求——运转这么些程序集所须要的批准。
    • 导出的品种。
  5. 命名空间和顺序集

    命名空间完全部独用立于程序集。
    在1个主次集中能够有两样的命名空间,一个命名空间也足以分布在多少个程序聚焦。
    取名空间是类名的1种扩充,属于类名范畴。

  6. 村办和共享程序集
    民用程序集在应用程序所在目录下或子目录中。
    个人程序集必要专注命名顶牛。
    动用共享程序集时,须要小心:程序集必须是独一无二的,有强名(唯一的称谓,强制的版本号)

  7. 扶助程序集
    帮衬程序集是只包括能源的程序集,它进一步适用于本地化。

  8. 翻看程序集
    ildasm,那是叁个MSIL反汇编制程序序。命令行运营ildasm,把程序集作为其参数或File|Open菜单。
    还有.NET Reflector之程序集。是用来深入分析程序集的工具。

 

自家的驾驭:

二、创设程序集
  1. 创立模块和程序集

    模块是3个并未有先后集个性的DLL。

    csc /target:module hello.cs
    创办模块hello.netmodule
    ildasm hello.netmodule查看那么些模块。

    /addmodule分选,可以把模块增添到存活的先后聚焦。

    创立二个A.cs类文件,然后csc /target:module A.cs编译,生成了A.netmodule文件,它不包罗程序集的消息;下面生成贰个顺序集B,它包罗模块A.netmodule,命令如下:csc /target:library /addmodule:A.netmodule /out:B.dll,然后利用IL翻看程序集:ildasm B.dll;如图所示:
    图片 1

    在利用IL查看程序集时,只好找到一个清单。

    模块的法力是更加快地运维程序集,因为不是全数类都在一个文本中,模块只在必要时加载。其余能够使程序集可以应用二种编制程序语言来创制。

  2. 程序集的属性

    • ./Solution Explorer/Properties/AssemblyInfo.cs文件,能够动用相似的源代码编辑器配置程序集的习性。
    • assembly前缀把质量标志为大局属性。
    • 次第集的全局属性与特定的言语成分非亲非故,用于程序集属性的参数是命名空间System.ReflectionSystem.Runtime.Compiler ServicesSystem.Runtime.InteropServices中的类。
    • System.Reflection取名空间中定义的主次集属性列表:

    图片 2
    在VS中,能够右键项目 - 属性 - 应用程序设置 - 程序集消息来配置那些属性:

    图片 3

    图片 4

  3. 动态加载和创建程序集
    在开垦时期,加多对先后集的引用,该程序集中的品种就可用来编写翻译器。
    能够成为加载程序集。为此可以接纳类Assembly的静态方法Load(),这么些办法是重载的,能够选拔AssemblyName给它传送程序集的名目或字节数组。
    事例:使用WPF,输入代码,点击按键实践并将结果展现到TextBlock中。
    图片 5

    创建类CodeProvider,定义方法CompileAndRun(),编译文本框中的代码,运转所生成的情势。代码如下:

    using System;
    using System.CodeDom.Compiler;
    using System.IO;
    using System.Reflection;
    using System.Text;
    using Microsoft.CSharp;
    namespace 动态加载和创建程序集
    {
     public class CodeProvider
     {
         private string prefix =
             "using System;"  
             "public static class Driver"  
             "{"  
             "public static void Run()"  
             "{";
    
         private string postfix =
             "}"  
             "}";
         public string CompileAndRun(string input, out bool hasError)
         {
             hasError = false;
             string returnData = null;
    
             CompilerResults results = null;
             using (CSharpCodeProvider provider = new CSharpCodeProvider())
             {
                 CompilerParameters options = new CompilerParameters();
                 options.GenerateInMemory = true;
    
                 StringBuilder sb = new StringBuilder();
                 sb.Append(prefix);
                 sb.Append(input);
                 sb.Append(postfix);
    
                 results = provider.CompileAssemblyFromSource(
                     options, sb.ToString());
             }
    
             if(results.Errors.HasErrors)
             {
                 hasError = true;
                 StringBuilder errorMessage = new StringBuilder();
                 foreach (CompilerError error in results.Errors)
                 {
                     errorMessage.AppendFormat("{0} {1}", error.Line, error.ErrorText);
                 }
    
                 returnData = errorMessage.ToString();
             }
             else
             {
                 TextWriter temp = Console.Out;
                 StringWriter writer = new StringWriter();
                 Console.SetOut(writer);
                 Type driverType = results.CompiledAssembly.GetType("Driver");
    
                 driverType.InvokeMember("Run", BindingFlags.InvokeMethod | BindingFlags.Static | BindingFlags.Public, null, null, null);
                 Console.SetOut(temp);
    
                 returnData = writer.ToString();
             }
    
             return returnData;
         }
    
     }
    }
    

    按钮的Click事件接二连叁到Compile_Click方法上:实例化CodeProvider类,调用方法CompileAndRun();从文本框textCode中领取输入,把结果写到TextBlock控件textOutput中:

    private void Compile_Click(object sender, RoutedEventArgs e)
         {
             CodeProvider driver = new CodeProvider();
             bool isError;
             textOutput.Text = driver.CompileAndRun(textCode.Text, out isError);
             if(isError)
             {
                 textOutput.Background = Brushes.Red;
             }
         }
    

    程序运转结果如图所示:

    图片 6

  4. 选拔程序域
    .NET的应用程序边界:应用程序域。

    运用托管IL代码,运转库就不能够访问同二个进度中的另3个应用程序的内部存款和储蓄器。五个应用程序能够运转在八个经过的几个利用程序域中。

    AppDomain类用于成立和间断应用程序域,加载和卸载程序集和类型、枚举域中的程序集和线程。

    事例:创造调节台程序AssemblyA,在Main()方式中加多Console.WriteLine(),再加多三个类Demo,其构造函数的参数是五个int值,用AppDomain类创建实例。

    namespace AssemblyA
    {
     class Program
     {
         static void Main(string[] args)
         {
             Console.WriteLine("Main in domain {0} called", AppDomain.CurrentDomain.FriendlyName); ;
             Console.ReadKey();
         }
     }
    }
    
    namespace AssemblyA
    {
    public class Demo
    {
        public Demo(int val1, int val2)
        {
            Console.WriteLine("Constructor with the values {0}, {1}"   " in domain {2} called", val1, val2, AppDomain.CurrentDomain.FriendlyName);
        }
    }
    }
    

    运营结果如下图所示:

    图片 7

    继而创制调整台程序DomainTest,首先利用AppDomain类的FriendlyName质量显示当前域的名称;调用CreateDomain()办法,创立1个新的行使程序域New AppDomain,然后把程序集AssemblyA加载到新域中,通过调用ExecuteAssembly()来调用Main()方法:

    namespace DomainTest
    {
     class Program
     {
         static void Main(string[] args)
         {
             AppDomain currentDomain = AppDomain.CurrentDomain;
             Console.WriteLine(currentDomain.FriendlyName);
    
             AppDomain secondDomain = AppDomain.CreateDomain("New AppDomain");
             secondDomain.ExecuteAssembly("AssemblyA.exe");
             /*secondDomain.CreateInstance(
                 "AssemblyA",
                 "AssemblyA.Demo",
                 true,
                 System.Reflection.BindingFlags.CreateInstance,
                 null,
                 new object[] { 7, 3 }, null, null, null);*/
    
             Console.ReadKey();
         }
     }
    }
    

    开发银行程序前先把Assembly.exe复制到当前项目目录下./bin/Debug,运营结果:
    图片 8

    看到第二行New AppDomain中新加载的顺序集的出口结果里看不到AssemblyA.exe的实施,因为没有开创新的进程;用CreateInstance()替代ExecuteAssembly()措施:它的首先个参数是程序集名称,第三个参数定义了应实例化的类,第四个参数true代表不区分轻重缓急写,System.Reflection.BindingFlags.CreateInstance是2个绑定标记枚举值,钦命应调用的构造函数;只必要将上边代码secondDomain.ExecuteAssembly("AssemblyA.exe");注释掉,下面/**/中的代码打消注释,运营结果如下:
    图片 9
    在运作时期,主应用程序域会自行创设。ASP.NET为各类运营在Web服务器上的Web应用程序创立1个应用程序域;Internet Explorer创制运维托管理控制件的应用程序域;对于应用程序,卸载程序集只好通过暂停应用程序域来拓展

    假如程序集是动态加载的,且要求在利用完后卸载程序集,应用程序域正是丰裕有效的。在主程序域中,不能去除已加载的程序集,但能够告一段落应用程序域,在该利用程序域中加载的保有程序集都会从内部存储器中革除出去。

    修改从前的WPF程序:增多2个新类,使用CreateInstanceAndUnwrap()实例化类CodeDriver,调用CompileAndRun()措施,之后再度卸载新利用程序域。
    ```
    namespace 动态加载和开创程序集
    {
    public class CodeDriverInAppDomain
    {
    public string CompileAndRun(string code, out bool hasError)
    {
    AppDomain codeDomain = AppDomain.CreateDomain("CodeDriver");
    CodeDriver codeDriver = (CodeDriver)
    codeDomain.CreateInstanceAndUnwrap(
    "动态加载和创办程序集",
    "动态加载和开创程序集.CodeDriver");
    string result = codeDriver.CompileAndRun(code, out hasError);

         AppDomain.Unload(codeDomain);
    
         return result;
     }
    

    }
    }

    要在另一个应用程序域中访问类`CodeDriver`,类`CodeDriver`就必须派生于基类`MarshalByRefObject`。所以`CodeDriver.cs`修改:
    

    namespace 动态加载和创办程序集
    {
    public class CodeDriver : MarshalByRefObject
    {
    ...
    }

    按钮事件处理程序可以修改为使用新类`CodeDriverInAppDomain`:
    

    private void Compile_Click(object sender, RoutedEventArgs e)
    {
    //CodeDriver driver = new CodeDriver();
    CodeDriverInAppDomain driver = new CodeDriverInAppDomain();
    bool isError;
    textOutput.Text = driver.CompileAndRun(textCode.Text, out isError);
    if(isError)
    {
    textOutput.Background = Brushes.Red;
    }
    }
    ``> 使用AppDomain类的GetAssemblies()`主意,能够查看应用程序域中加载的顺序集。

  5. 共享程序集
    共享程序集必须有一个强名
    共享程序集必须有1个强名,来唯壹地方统一规范识该程序集。
    强名由以下组成:

    • 程序集自身的名号
    • 版本号
    • 公钥
    • 文化

为了唯一地方统一规范识企业中的程序集,应使用命名空间档期的顺序结构来给类命名。

查看全局程序集缓存:在`C:Windowsassembly `  目录下 。
程序集查看器可以使用Windows资源管理器查看和删除程序集。`gacutil.exe`工具可以使用命令行安装、卸载和显示程序集。

**创建共享程序集**

确立3个Visual C# Class Library项目SharedDemo;命名空间Wrox.ProCSharp.Assemblies.Sharing,类名SharedDemo
类的构造函数把文件的有所行都将读取到2个群集中;文件名作为参数字传送送给构造函数;方法GetQuoteOfTheDay()只回去这一个集结的七个Infiniti制字符串。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace Wrox.ProCSharp.Assemblies.Sharing
{
    public class SharedDemo
    {
        private List<string> quotes;
        private Random random;

        public SharedDemo(string filename)
        {
            quotes = new List<string>();
            Stream stream = File.OpenRead(filename);
            StreamReader streamReader = new StreamReader(stream);
            string quote;
            while ((quote = streamReader.ReadLine()) != null)
            {
                quotes.Add(quote);
            }
            streamReader.Close();
            stream.Close();
            random = new Random();
        }

        public string GetQuoteOfTheDay()
        {
            int index = random.Next(1, quotes.Count);
            return quotes[index];
        }
    }
}

要共享那几个程序集,要求二个强名,使用强名工具(sn):sn -k mykey.snk,强名工具生成和编辑3个公钥/私钥对,并把改密钥对写到文件中。
在VS中,能够挑选签名(signing)选项卡,用项目性质标识程序集。
图片 10
安装了signing选项后,重新树立文件后,公钥就在先后集清单中。
图片 11

**安装共享程序集**

先后聚集有了公钥后就能够动用全局程序集缓存工具gacutil及其/i采用把它安装到全局程序集缓存中:
gacutil /i SharedDemo.dll
用VS配置现在创建的事件命令行,就足以在大局程序集缓存中装置各类成功组建的程序集。

摘自《C#搞基程序设计》

图片 12

)

程序集是五个大要上的概念,2个门类更动的exe恐怕dll都足以称为二个程序集,internal修饰的内容能够在先后集内可知。

C#之程序集

 

本文由bwin必赢发布,转载请注明来源

关键词: .net web技术 NET