【读书笔记】C#高级编程 第十九章 程序集
(一)程序集的含义
程序集是.NET用于部署和配置单元的术语。
.NET应用程序包含一个或多个程序集。通常扩展名是EXE或DLL的.NET可执行程序称为程序集。
程序集是自我描述的安装单元,由一个或多个文件组成。程序集可以是私有或共享的。
1、程序集的功能
- 程序集是自描述的。
- 版本的相互依赖在程序集的清单中进行了记录。
- 程序集可以并行加载。
- 应用程序使用应用程序域来确保其独立性。
- 安装非常简单。
2、程序集的结构
程序集由描述它的程序集元数据、描述导出类型和方法的类型元数据、MSIL代码和资源组成。所有这些部分都在一个文件中,或者分布在几个文件中。
3、程序集清单
程序集的一个重要部分是程序集清单,它是元数据的一部分,描述了程序集和引用它所需要的所有信息,并列出了它所有的依赖关系。
- 标识(名称、版本、文化和公钥)。
- 属于该程序集的一个文件列表。
- 被引用程序集的列表。
- 一组许可请求——运行这个程序集需要的许可。
- 导出的类型,假定它们在一个模块中定义,该模块从程序集中引用,程序集就包含他们;否则它们就不是程序集清单的一部分。
4、名称空间和程序集
名称空间完全独立于程序集。名称空间只是类型名的一种扩展,它属于类型名的范畴。
5、私有程序集和共享程序集
私有程序集或者位于应用程序所在的同一个目录下,或者位于其子目录中。在使用共享程序集时,程序集必须是唯一的,因此,必须有一个唯一的名称(称为强名)。
6、附属程序集
附属程序集是只包含资源的程序集,它尤其适用于本地化。
(二)构建程序集
1、创建程序集
在Visual Studio中,所有的C#项目都会创建一个程序集,无论是DLL还是EXE。
2、程序集的特性
1 using System.Reflection;
2 using System.Runtime.CompilerServices;
3 using System.Runtime.InteropServices;
4
5 // 有关程序集的一般信息由以下
6 // 控制。更改这些特性值可修改
7 // 与程序集关联的信息。
8 [assembly: AssemblyTitle("ConsoleApp4")]
9 [assembly: AssemblyDescription("")]
10 [assembly: AssemblyConfiguration("")]
11 [assembly: AssemblyCompany("")]
12 [assembly: AssemblyProduct("ConsoleApp4")]
13 [assembly: AssemblyCopyright("Copyright 2017")]
14 [assembly: AssemblyTrademark("")]
15 [assembly: AssemblyCulture("")]
16
17
18 // 将 ComVisible 设置为 false 会使此程序集中的类型
19 //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
20 //请将此类型的 ComVisible 特性设置为 true。
21 [assembly: ComVisible(false)]
22
23
24 // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
25 [assembly: Guid("0f9598cd-b504-4b26-bbbb-0ccf74f16781")]
26
27
28 // 程序集的版本信息由下列四个值组成:
29 //
30 // 主版本
31 // 次版本
32 // 生成号
33 // 修订号
34 //
35 // 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
36 // 方法是按如下所示使用“*”: :
37 // [assembly: AssemblyVersion("1.0.*")]
38 [assembly: AssemblyVersion("1.0.0.0")]
39 [assembly: AssemblyFileVersion("1.0.0.0")]
以上代码用于配置程序集清单。
assembly:前缀把特性标记为程序集级别特性。
3、创建和动态加载程序集
要动态的编译C#代码,可以使用Microsoft.CSharp名称空间中的CSharpCodeProvider类。
(三)应用程序域
在.NET体系结构中,应用程序除了以前的进程边界以外有了一个新的边界:应用程序域。使用托管IL代码,运行库可以确保在同一个进程中不能访问另一个应用程序的内存。多个应用程序可以运行在一个进程的多个应用程序域中。
AppDomain类用于创建和终止应用程序域,加载、卸载程序集和类型,以及枚举应用程序域中的程序集和线程。
1 namespace ConsoleApp6
2 {
3 class Program
4 {
5 static void Main(string[] args)
6 {
7 AppDomain currentDomain = AppDomain.CurrentDomain;
8 Console.WriteLine(currentDomain.FriendlyName);//输出当前程序集的程序域
9 AppDomain secondDomain = AppDomain.CreateDomain("New AppDomain");
10 secondDomain.ExecuteAssembly("ConsoleApp5.exe");//ConsoleApp5.exe需要放置到bin\Debug文件夹中
11 secondDomain.CreateInstance("ConsoleApp5", "ConsoleApp5.Demo", true, System.Reflection.BindingFlags.CreateInstance, null, new object[] { 1, 2 }, null, null);//需要引用ConsoleApp5
12 }
13 }
14 }
15
16 namespace ConsoleApp5
17 {
18 class Program
19 {
20 static void Main(string[] args)
21 {
22 Console.WriteLine("我是程序集ConsoleApp5.exe");
23 Console.ReadKey();
24 }
25 }
26 public class Demo
27 {
28 public Demo(int val1, int val2)
29 {
30 Console.WriteLine("Constructor with the values {0}, {1} in domain " + "{2} called", val1, val2, AppDomain.CurrentDomain.FriendlyName);
31 }
32 }
33 }
如果程序集是动态加载的,且需要在使用完以后卸载程序集,应用程序域就非常有用。在主程序于中,不能删除已加载的程序集,但可以终止应用程序域,在该应用程序域中加载的所有程序集都会从内存中清除。
1 class Program
2 {
3 static void Main(string[] args)
4 {
5 AppDomain codeDomain = AppDomain.CreateDomain("CodeDriver");
6 var dirver = new CodeDriver();
7 codeDomain.CreateInstanceAndUnwrap("ConsoleApp5", "ConsoleApp5.CodeDriver");
8 bool isError;
9 string textOutput = dirver.CompileAndRun(Console.ReadLine(), out isError);
10 if (isError)
11 {
12 Console.WriteLine("Error");
13 }
14 Console.WriteLine(textOutput);
15 AppDomain.Unload(codeDomain);
16 Console.ReadKey();
17 }
18 }
19 public class CodeDriver : MarshalByRefObject//类需继承MarshalByRefObject类,否则无法跨应用程序域访问
20 {
21 private string prefix = "using System;" +
22 "public static class Driver" +
23 "{" +
24 " public static void Run()" +
25 "{";
26 private string postfix = "}}";
27 public string CompileAndRun(string input, out bool hasError)
28 {
29 hasError = false;
30 string returnData = null;
31
32 CompilerResults results = null;
33 using (var provider = new CSharpCodeProvider())
34 {
35 var options = new CompilerParameters();
36 options.GenerateInMemory = true;
37
38 var sb = new StringBuilder();
39 sb.Append(prefix);
40 sb.Append(input);
41 sb.Append(postfix);
42
43
44 results = provider.CompileAssemblyFromSource(options, sb.ToString());
45 }
46
47
48 if (results.Errors.HasErrors)
49 {
50 hasError = true;
51 var errorMessage = new StringBuilder();
52 foreach (CompilerError error in results.Errors)
53 {
54
55 errorMessage.AppendFormat("{0} {1}", error.Line, error.ErrorText);
56 }
57 }
58 else
59 {
60 TextWriter temp = Console.Out;
61 var writer = new StringWriter();
62 Console.SetOut(writer);
63 Type driverType = results.CompiledAssembly.GetType("Driver");
64 driverType.InvokeMember("Run", BindingFlags.InvokeMethod | BindingFlags.Static | BindingFlags.Public, null, null, null);
65 Console.SetOut(temp);
66 returnData = writer.ToString();
67 }
68 return returnData;
69 }
70 }
(四)共享程序集
共享程序集一般安装在全局程序集缓存(GAC)中。
1、强名
共享程序集名必须是全局唯一的,并且必须可以保护该名称。任何其他人不能使用同一个名称创建程序集。
强名是一个简单的文本名称、附带版本号、公钥和文化。
2、使用强名获得完整性
在创建共享组件时,必须使用公钥/私钥对。
3、全局程序集缓存
全局程序集缓存(Global Assembly Cache,GAC)是全局使用的程序集缓存。大多数共享程序集都安装在这个缓存中,也可以使用共享目录(也在服务器上)。
GAC位于(如果没有修改VS的安装路径可参考:C:\Windows\assembly)目录下。
(五)配置.NET应用程序
1、配置类别
- 启动设置——用于指定需要的运行库版本。
- 运行库设置——用于指定运行库如何进行垃圾回收,如何进行程序集绑定。
- WCF设置——用于利用WCF配置应用程序。
- 安全设置——加密配置和许可。
以下三种配置使用这些设置:
- 应用程序配置文件——包含应用程序的特性设置,如程序集的绑定信息,远程对象的配置等。这个配置文件放在可执行文件所在的目录下,例如web.config。
- 计算机配置文件——可以用于系统范围的配置(位于)。
- 发行者策略文件——由组件的创建者用于指定共享程序集可以与旧版本兼容。
2、绑定程序集
如果要在应用程序之间共享一个程序集,但不希望它在全局程序集缓存中共享它,就可以把该程序集放在一个共享目录中。
查找程序集的正确目录有两种方式:使用XML配置文件中的codeBase元素(仅用于共享程序集),或者使用probing元素(可用于私有和共享程序集)。
(1)<codeBase>
<configuration>
<runtime>
<assemblyBinding xml="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="ShardDemo" culture="neutral" publicKeyToken="f946433fdae2512d"/>
<codeBase version="1.0.0.0" href="http://www.christiannagel.com/WroxUtil2/SharedDemo.dll"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
<codeBase>元素有特性version和href,使用version特性必须指定程序集的原始引用版本,使用href特性可以定义应从中加载程序集的目录。上面的例子,使用的是一个远程路径的共享程序集。
(2)<probing>
如果没有配置<codeBase>元素,程序集也没有存储在全局程序集缓存中,运行库就会利用probing元素来查找程序集。.NET运行库会在应用程序目录或与所搜索程序集同名的子目录中查找文件扩展名为.dll和.exe的程序集。
<configuration>
<runtime>
<assemblyBinding xml="urn:schemas-microsoft-com:asm.v1">
<probling privatePath="bin;utils;"/>
</assemblyBinding>
</runtime>
</configuration>
<probing>元素只有一个必需的privatePath特性。上面的例子告诉运行库,在应用程序的根目录下搜索程序集,再在bin和util目录中搜索。
(六)版本问题
1、版本号
程序集的版本号由四部分组成:
<Major>.<Minor>.<Build>.<Revision>.
如果进行的改动与以前的兼容则改变Build和Revision,否则,修改Major和Minor。Build的值是自2000年1月1日以来的天数,Revsion的值是自午夜开始的秒数除以2。
2、通过编程方式获取版本
Console.WriteLine(Assembly.GetExecutingAssembly().FullName);
3、绑定到程序集版本
使用配置文件可以指定应绑定到共享程序集的另一个版本。
<configuration>
<runtime>
<assemblyBinding xml="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="ShardDemo" culture="neutral" publicKeyToken="f946433fdae2512d"/>
<bindingRedirect oldVersion="1.0.0.0-1.0.3300.0" newVersion="1.0.3300.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
为了重定向到另一个版本上,要使用<bindingRedirect>元素。oldVersion特性指定应把程序集的那个版本重定向到新版本上。使用oldVersion特性可以指定一个范围,例如应重定向1.0.0.0-1.0.3300.0之间的所有程序集版本。新版本用newVersion特性指定。
4、发行者策略文件
使用全局程序集缓存中的共享程序集,可以使用发行者策略避免版本冲突问题。创建发行者策略文件,把所有这些应用程序重新定向到指定共享程序集的新版本上。
(1)创建发行者策略文件
发行者策略文件是一个把已有版本或某个版本范围重定向到新版本的XML文件。
(2)创建发行者策略程序集
要把发行者策略文件与共享程序集关联起来,必须创建一个发行者策略程序集,并把它放到全局程序集缓存中。
(3)将发行者策略程序集添加到全局程序集缓存中
(4)重写发行者策略
添加XML<publisherPolicy>元素和apply="no"特性,就可以禁用发行者策略。
<configuration>
<runtime>
<assemblyBinding xml="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="ShardDemo" culture="neutral" publicKeyToken="f946433fdae2512d"/>
<publisherPolicy apply="no"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
5、运行库的版本
不仅可以安装和使用程序集的多个版本,还可以安装和使用.NET运行库(CLR)的多个版本。
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6" />
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1"/>
</startup>
</configuration>
<supportedRuntime>的顺序可以定义系统上可用的运行库版本的优先级,sku特性定义了.NET Framework的版本。
【读书笔记】C#高级编程 第十九章 程序集的更多相关文章
- 读书笔记 - js高级程序设计 - 第十五章 使用Canvas绘图
读书笔记 - js高级程序设计 - 第十三章 事件 canvas 具备绘图能力的2D上下文 及文本API 很多浏览器对WebGL的3D上下文支持还不够好 有时候即使浏览器支持,操作系统如果缺缺 ...
- 读书笔记 - js高级程序设计 - 第十二章 DOM2和DOM3
Node类型的变化 访问元素的样式 myDiv.style.backgroundColor = "red" myDiv.style.width = "100px& ...
- R in action读书笔记(19)第十四章 主成分和因子分析
第十四章:主成分和因子分析 本章内容 主成分分析 探索性因子分析 其他潜变量模型 主成分分析(PCA)是一种数据降维技巧,它能将大量相关变量转化为一组很少的不相关变量,这些无关变量称为主成分.探索性因 ...
- R in action读书笔记(16)第十二章 重抽样与自助法之 置换检验
第十二章:重抽样与自助法 本章,我们将探究两种应用广泛的依据随机化思想的统计方法:置换检验和自助法 12.1 置换检验 置换检验,也称随机化检验或重随机化检验. 有两种处理条件的实验,十个受试者已经被 ...
- 【读书笔记】C#高级编程 第二十二章 安全性
(一)身份验证和授权 安全性的两个基本支柱是身份验证和授权.身份验证是标识用户的过程,授权在验证了所标识用户是否可以访问特性资源之后进行的. 1.标识和Principal 使用标识可以验证运行应用程序 ...
- 【读书笔记】C#高级编程 第二十五章 事务处理
(一)简介 事务的主要特征是,任务要么全部完成,要么都不完成. (二)概述 事务由事务管理器来管理和协调.每个影响事务结果的资源都由一个资源管理器来管理.事务管理器与资源管理器通信,以定义事务的结果. ...
- 【读书笔记】C#高级编程 第二十四章 文件和注册表操作
(一)文件和注册表 对于文件系统操作,相关的类几乎都在System.IO名称空间中,而注册表操作由System.Win32名称空间中的类来处理. (二)管理文件系统 System.MarshalByR ...
- 【读书笔记】C#高级编程 第十六章 错误和异常
(一)简介 错误的出现并不总是编写应用程序的人的原因,有时应用程序会因为应用程序的最终用户引发或运行代码的环境而发生错误.C#提供了异常处理机制来处理错误. (二)异常类 在C#中,但刚出现某个特殊的 ...
- 【读书笔记】C#高级编程 第十五章 反射
(一)在运行期间处理和检查代码 自定义特性允许把自定义元数据与程序元素关联起来.反射是一个普通术语,它描述了在运行过程中检查和处理程序元素的功能.例如,反射允许完成的任务: 枚举类型的成员 实例化新对 ...
随机推荐
- iftop使用
在linux中监控系统资源.进程.内存占用等信息,可以使用top命令. 查看网络状态可以使用netstat工具. 如果想查看实时的网络流量,监控TCP/IP连接等,则可以使用iftop工具. 一.if ...
- python超级有用的实战项目,拿走不谢~
写在前面的一点P话: Python是目前最好的编程语言之一.由于其可读性和对初学者的友好性,已被广泛使用. 那么要想学会并掌握Python,可以实战的练习项目是必不可少的. 直接上第一个项目~ 猜字游 ...
- Python使用腾讯云-短信服务发送手机短信
目前[腾讯云短信]为客户提供[国内短信].[国内语音]和[海外短信]三大服务,腾讯云短信SDK支持以下操作: 国内短信 国内短信支持操作: • 指定模板单发短信 • 指定模板群发短信 • 拉取短信回执 ...
- NC13328 倒水
NC13328 倒水 题目 题目描述 有一个大水缸,里面水的温度为 \(T\) 单位,体积为 \(C\) 升.另有 \(n\) 杯水(假设每个杯子的容量是无限的),每杯水的温度为 \(t[i]\) 单 ...
- SpringBoot启动代码和自动装配源码分析
随着互联网的快速发展,各种组件层出不穷,需要框架集成的组件越来越多.每一种组件与Spring容器整合需要实现相关代码.SpringMVC框架配置由于太过于繁琐和依赖XML文件:为了方便快速集成第三 ...
- c# 反射专题—————— 介绍一下是什么是反射[ 一]
前言 为什么有反射这个系列,这个系列后,asp net 将会进入深入篇,如果没有这个反射系列,那么asp net的源码,看了可能会觉得头晕,里面的依赖注入包括框架源码是大量的反射. 正文 下面是官方文 ...
- 2022宁波市第五届网络安全大赛MISC方向部分wp
BlackAndWhite 1. 得到了三百多张黑白颜色的图片,将白色图片转为数字0,黑色图片转为数字1,得到二进制字符串 01100110011011000110000101100111011110 ...
- elasticsearchTemplate that could not be found
***************************APPLICATION FAILED TO START*************************** Description: Metho ...
- MySQL sql优化(摘抄自文档)
前言 有人反馈之前几篇文章过于理论缺少实际操作细节,这篇文章就多一些可操作性的内容吧. 注:这篇文章是以 MySQL 为背景,很多内容同时适用于其他关系型数据库,需要有一些索引知识为基础. 优化目标 ...
- 解决 Vue 部署在域名子路由 问题
我们先看下官方说明 默认情况下,Vue CLI 会假设你的应用是被部署在一个域名的根路径上,例如 https://www.my-app.com/ .如果应用被部署在一个子路径上,你就需要用这个选项指定 ...