【C#基础概念】程序集与托管模块的概念
本文是为了学习程序集而整理的网上资料,主要包括两个部分,概念和使用,前部分讲怎样理解程序集,后部分讲述怎样使用的细节。
程序集与托管模块的概念
我相信现在大家对程序集和托管模块分别是什么以及两者间的关系有了较好的理解。但是如果有源代码辅助一下那就更好了。是的。对程序员来说,源代码比什么都亲切。好的,下面就举两个简单的例子(用C#语言表述)。一个是单模块程序集,一个是多模块程序集。两者都是前台程序集(后缀名是exe)。我用Visual
C# 2003 集成开发环境试了一下,竟然发现它不支持多程序集的开发(希望是我没有找到)。没关系,我们还有DotNet FrameWork
SDK呢,不用怕。它自带的C#编译器csc.exe很好用。至于csc的用法我就不多说了。
csc hello.cs,这个命令默认的是生成 .exe文件,也就是一个主托管模块。
现在到hello.cs所在的文件夹中看看,你会发现一个新文件hello.exe。好,一个主托管模块诞生了。既然有主托管模块,那么就标志着一个程序集的诞生。再看看,没有其他的托管模块,那么这个程序集就是一个单模块程序集。
Cat.netmodule, Main.exe 。我们习惯说这个程序集是Main.exe 。但是一定要知道,Main.exe
其实是一个程序集的“头头”,由它代表着整个程序集。
程序集的使用
相信有了上面的介绍之后大家对程序集的概念及建立都有点清楚下面的文章载自博客圆:http://www.cnblogs.com/stzyw/archive/2005/08/25/222361.aspx
任何.NET二进制代码使用的.NET运行时是一个或一组程序集组成的。当你编译一个应用程序时,实际上是在创建一个程序集。
任何时候构建一个EXE或DLL文件时必须使用/t:library编译参数创建与该应用程序相对应的包含清单(manifest)的程序集,清单(manifest)记录了.NET运行时程序集的相关信息。另外,使用/t:module编译参数, 当编译应用程序或使用程序集生成工具(the Assembly Generation tool)时必须使用/addmodule开关将这个DLL文件加入到其他程序集中。
清单数据(Manifest Data)
程序集的清单有不同的方法存储。若编译一个独立的应用程序或DLL文件,清单与程序或DLL的PE结合在一起,这称为单一文件的程序集(single-file assembly)。多文件程序集(multifile assembly)是指清单以另外一个独立实体的形式作为程序集的一部分,或者作为程序集中的一个模块。
同样程序集的定义很大程度取决你如何使用它。从客户的角度来看,程序集是模块、导出类型、(必需、可选)资源的命名和版本化(versioned)的集合。从程序集创建者的角度来看,程序集是客户能使用的一组相关联的模块、类型、资源、导出的方法的封装包(mean of packaging)。也就是说,清单是程序集和用户之间沟通的桥梁。下面列出程序集中清单包含的信息:
· 程序集名称(Assembly name)
· 版本信息(Versioning information)
版本信息是由四个不同的部分组成的版本号,分别是主版号、子版号、构建序号、修订号。
· (可选的)共享名和带符号的程序集散列(An(Optional)shared name and signed assembly hash)
主要是关于程序集部署的相关信息。
· 文件(Files)
包含在程序集中的文件列表。
· 引用的程序集(Referenced assemblies)
直接引用的外部程序集列表。
· 类型(Types)
程序集内部的所有类型及模块映像包含的类型的列表。(This is list of all types in the assembly with a mappig to containing the type.)
· 安全(Security)
安全权限的列表,权限已明确地被程序集抛弃。(permissions This is a list of security permissions that are explicity refused by the assembly.)
· 定制属性(Custom attributes)
· 产品信息 包含公司、商标、产品及版权信息。
程序集的优势
· 程序集的封装:将多个模块封装到一个物理文件,起到性能优化的作用。当你创建一个应用程序并使用多文件程序集时,.NET运行时只需加载相关的模块。这种策略起到减少应用程序的工作集。
· 程序集的部署
在.NET框架中程序集是最小的部署单元。虽然它诱人的说,程序集是部署应用程序的方法,但是技术上并不是如此。许多关于程序集部署的正确的观点是:在.NET中程序集应该看作一个窗体的类部署(class deployment)-就像Win32中的一个DLL文件。一个单独的应用程序是由多个程序组成的。
因为程序集是自描述的(self-desciribing),所以部署程序集最简单的方法就是直接把程序集复制到目的文件夹。当尝试运行包含这个程序集的应用程序时,清单将向.NET运行时提供包含在这个程序集中的方法信息。另外,清单(manifest)也向应用程序提供该程序集所引用的外部程序集的相关信息。
许多通过公共方法部署的程序集依然是私有的程序集,即程序集被复制到文件夹,但它们不是共享的。缺省情况下程序集是私有的,除非明确地指定程序集为共享程序集(shared assembly)。
· 程序集的版本
使用程序集另外一个主要优势是程序集内置了版本号。程序集中止了DLL地狱。DLL地狱是指当一个应用程序重写了一个被其他应用程序引用的DLL文件,而该应用程序引用的是低版本的同名DLL文件,这就造成了引用低版本DLL的应用程序运行出错,这种情况。虽然Win32资源文件格式内置了版本资源类型,但是操作系统不会强制执行任何版本控制,以便依赖这个DLL文件的应用程序能正常运行。
基于这个问题,清单不仅包含程序集本身的版本信息,也包含了该程序集所有被引用的程序集和这些程序集的版本信息。因为有了这个体系结构,.NET运行时能确保版本规则被支持,当出现新版本的程序集时,版本不兼容的共享DLLs由操作系统自动安装,使得应用程序可以继续正常运行。
用多个模块创建程序集(Creating Assembies with Multiple Modules)
模块是基于DLL,但是它不是真正意义上的DLL,它必须被包含程序集中。示例:
// NetModuleTestServer.cs
// Build with the following command-line switches:
// csc /t:library NetModuleTestServer.cs
public class NetModuleTestServer
{
public static void Bar()
{
System.Console.WriteLine("NetModuleTestServer.Bar(NetModuleTestServer.netmodule)");
}
}
// NetModuleTestClientApp.cs
// Build with the following command-line switches:
//
// csc addmodule:NetModuleServer.netmodule NetModuleTestClientApp.cs
using System;
using System.Diagnostics;
using System.Reflection;
class NetModuleTestClientApp
{
public static void Main()
{
Assembly DLLAssembly = Assembly.GetAssembly(
typeof(NetModuleTestServer));
Console.WriteLine(""nNetModuleTestServer.dll Assembly " +
"Information");
Console.WriteLine(""t" + DLLAssembly);
Process p = Process.GetCurrentProcess();
string AssemblyName = p.ProcessName + ".exe";
Assembly ThisAssembly = Assembly.LoadFrom(AssemblyName);
Console.WriteLine("NetModuleTestClient.exe Assembly " +
"Information");
Console.WriteLine(""t" + ThisAssembly + ""n");
Console.WriteLine("Calling NetModuleTestServer.Bar
");
NetModuleTestServer.Bar();
}
}
创建共享程序集
若要创建一个在多个应用程序使用的程序集,并且版本信息相当重要,则必须共享程序集。若要共享程序集,必须给程序集指定强名称。可以通过.NET SDK提供强名称工具(the Strong Name tool)创建强名称。使用强名称有四个主要理由:
· 它是.NET生成唯一的全局名称的机制
·
因为强名称工具生成的密钥对包含了一个签名,你可以判断程序集创建之后是否被篡改。(Because the generated key pair
includes a singature,you can tell whether an assembly has been tampered
with after its original creation.)
· 强名称能防止第三方在你构建的程序集的基础上发表新的版本。这是因为密钥对包含签名起了作用,因为第三方不知道你的私钥。
·
当.NET加载程序集时,运行时会自动验证调用者是否合法。(When .NET load an assembly,the runtime can
verify that the assembly came from the publisher that the caller is
expecting.)
创建强名称的步骤:
· 使用强名称工具为程序集创建一个强名称。示例:
sn -k InsideCSharp.key
· 在客户端源代码文件中添加属性AssemblyKeyFile,把强名称指定给程序集。
使用全局程序集缓存工作
.NET每次加载程序集时都会创建一个代码缓存区,通常成为全局程序集缓存。使用全局程序集缓存有三个作用:
· 存储从Internet或文件服务器下载的代码。注:从一个特定的应用程序加载的代码存储在缓冲中的私有区域,以防止其他程序集访问。
· 存储被多个.NET应用程序共享的组件数据。利用全局缓存工具将程序集加载到缓存全局区域,使得该程序集可以被本地机器的所有应用程序访问。
· 程序集的本地代码是预运行时编译的,同时存储在全局程序集缓存区。(native code versions of assemblies that have been preJITted are stored in the cache.)
缓存视图
1、在windows"assembly文件夹中可以查看程序集的相关信息,如版本号、语言(culture)、公钥标记等等信息。
2、在命令行使用gacutil。其中-i参数:加载程序集;-u参数:卸载程序集(可以指定版本号)、-l参数:列出程序集的相关信息。
// DllTestServer.cs
// Build with the following command-line switches:
// csc /t:library DllTestServer.cs
public class DllTestServer
{
public static void Foo()
{
System.Console.WriteLine("DllTestServer.Foo " +
"(DllTestServer.DLL)");
}
}
// DllTestClient.cs
// Build with the following command-line switches:
// csc DllTestClient.cs /r:DllTestServer.dll
using System;
using System.Diagnostics;
using System.Reflection;
class DllTestClientApp
{
public static void Main()
{
Assembly DLLAssembly =
Assembly.GetAssembly(typeof(DllTestServer));
Console.WriteLine(""nDllTestServer.dll Assembly " +
"Information");
Console.WriteLine(""t" + DLLAssembly);
Process p = Process.GetCurrentProcess();
string AssemblyName = p.ProcessName + ".exe";
Assembly ThisAssembly = Assembly.LoadFrom(AssemblyName);
Console.WriteLine("DllTestClient.exe Assembly " +
"Information");
Console.WriteLine(""t" + ThisAssembly + ""n");
Console.WriteLine("Calling DllTestServer.Foo
");
DllTestServer.Foo();
}
}【C#基础概念】程序集与托管模块的概念的更多相关文章
- 【C#进阶系列】02 PE文件,程序集,托管模块,元数据——还是那个Hello world
好了,还是这张图,还是一样的Hello world. 因为本章其实很多都是讲一些命令行编译啊什么鬼的配置类的东西,要用的时候直接百度或者回头查书就可以了, 所以了解一下也就行了,也没有记录下来,接下来 ...
- 程序集的内部结构(托管模块、元素局、IL代码的分布情况)
程序集的内部结构 在看程序集的结构之前,我们先来看托管模块的结构. 托管模块由四部分组成:PE32头.CLR头.元数据(Metadata).IL代码.其中PE32头是用来决定托管模块运行的系统环境(3 ...
- [CLR via C#]1.2 将托管模块合并成程序集
原文:[CLR via C#]1.2 将托管模块合并成程序集 1.CLR是不和托管模块一起工作的,CLR是和程序集一起工作的. 2. 程序集是一个或多个托管模块/资源文件的逻辑性分组. 3. 程序 ...
- .Net Framework 之 托管模块与程序集的关系
一.基本概念: --托管模块:一个标准的32的可移植执行体(PE32)文件或一个标准的64位可移植执行体(PE32+)文件.由用支持CLR的任何一种语言创建的源代码文件,再经过相应的编译器检查语法和分 ...
- 【CLR via C#】CSC将源代码编译成托管模块
下图展示了编译源代码文件的过程.如图所示,可用支持 CLR 的任何一种语言创建源代码文件.然后,用一个对应的编译器检查语法和分析源代码.无论选用哪一个编译器,结果都是一个托管模块(managedmod ...
- 程序集(Assembly)和模块(Managed Module)
前言 一直都用集成开发坏境(IDE),一直对模块和程序集的概念理解的不是很直观,因为一Build就把你的单个模块塞进程序集里面去了.当然,对你的编程也不会造成太大的影响.但有些东西你最好还是知道比较好 ...
- 一、源代码-面向CLR的编译器-托管模块-(元数据&IL代码)
本文脉络图如下: 1.CLR(Common Language Runtime)公共语言运行时简介 (1).公共语言运行时是一种可由多种编程语言一起使用的"运行时". (2).CLR ...
- Python进阶----计算机基础知识(操作系统多道技术),进程概念, 并发概念,并行概念,多进程实现
Python进阶----计算机基础知识(操作系统多道技术),进程概念, 并发概念,并行概念,多进程实现 一丶进程基础知识 什么是程序: 程序就是一堆文件 什么是进程: 进程就是一个正在 ...
- 零基础Python教程-函数及模块的使用
函数 在学习本节内容之前,我们先来一起做道数学题. 已知:半径分别为0.1.0.2.0.3的三个圆,分别求这三个圆的面积. 很多读者可能要笑一下,这不是小学的数学问题吗? S = π * r * r ...
随机推荐
- 『德不孤』Pytest框架 — 2、Pytest的基本使用
目录 1.Pytest安装 2.Pytest常用插件 3.Pytest运行的第一个例子 4.Pytest框架的运行方式 5.在PyCharm中以Pytest的方式运行测试用例 1.Pytest安装 C ...
- HashSet 实现类
HashSet 实现类 通过 HashCode 判断元素是否存在,若存在则不添加,否则添加以此实现唯一性 常用方法 Modifier and Type Method and Description b ...
- Flink 如何通过2PC实现Exactly-once语义 (源码分析)
Flink通过全局快照能保证内部处理的Exactly-once语义 但是端到端的Exactly-once还需要下游数据源配合,常见的通过幂等或者二阶段提交这两种方式保证 这里就来分析一下Sink二阶段 ...
- 使用Hot Chocolate和.NET 6构建GraphQL应用(3) —— 实现Query基础功能
系列导航 使用Hot Chocolate和.NET 6构建GraphQL应用文章索引 需求 在本文中,我们通过一个简单的例子来看一下如何实现一个最简单的GraphQL的接口. 实现 引入Hot Cho ...
- CSS之 sass、less、stylus 预处理器的使用方式
更详细区别参考文档:https://blog.csdn.net/pedrojuliet/article/details/72887490 使用变量: sass: 使用 $ 符号定义变量,如: $ba ...
- NOIP2020 部分简要题解
C 首先考虑 \(n = 2\) 怎么做. 可以发现的是我们一定要借助空柱子 \(n + 1\),并且两个柱子都必须要移动. 注意到此时本质上就是将两种球分类,于是我们考虑能否将一个柱子上两种颜色分开 ...
- NOIP2018 Day2T3 保卫王国
首先不考虑强制要求的话是一个经典问题,令 \(f_{i, 0 / 1}\) 为 \(i\) 选或不选时以 \(i\) 为根的子树的最优答案.那么就有转移 \(f_{u, 0} = \sum f_{v, ...
- java中静态代码块详解
感谢大佬:https://blog.csdn.net/qq_35868412/article/details/89360250 今天在项目中看到这行代码,静态代码块,很久没用静态代码块了,今天来复习一 ...
- 在TCP文件传输中如何判断java流的末尾
感谢前辈们的解答:https://bbs.csdn.net/topics/280085530 问题描述: 服务端向客户端发送数据流,服务端发完了数据不关闭流. 我在客户端读流,我无法读到-1,所以无法 ...
- CSS 圆角框
转载请注明来源:https://www.cnblogs.com/hookjc/ 其实这种圆角框是靠一个个容器堆砌而成的,每一个容器的宽度不同,这个宽度是由margin外边距来实现的,如:margin: ...