C# 中 Assembly 类详解

Assembly 类位于 System.Reflection 命名空间,表示一个可重用、可部署且可版本化的 .NET 程序集。程序集是 .NET 应用程序的基本构建块,包含了类型、资源、元数据和清单。通过 Assembly 类,你可以加载程序集 、查询类型信息 、动态创建实例 、读取自定义特性 、访问嵌入资源等。

1. 如何获取 Assembly 对象

1.1 静态方法(常用)

方法 说明
Assembly.GetExecutingAssembly() 获取当前正在执行的代码所在的程序集。
Assembly.GetCallingAssembly() 获取调用当前方法的方法所在的程序集(性能稍差,慎用)。
Assembly.GetEntryAssembly() 获取应用程序的入口程序集(通常是可执行文件)。
Assembly.Load() 通过程序集的显示名称 或字节数组加载程序集。
Assembly.LoadFrom() 从指定文件路径加载程序集(会加载依赖项)。
Assembly.LoadFile() 仅加载指定路径的程序集,不自动加载依赖项。
Assembly.ReflectionOnlyLoadFrom() 仅用于反射(不可执行代码),.NET Core 5+ 不支持。
复制代码
 using System.Reflection;
 ​
 // 1. 获取当前程序集
 Assembly asm1 = Assembly.GetExecutingAssembly();
 ​
 // 2. 通过名称加载(需已存在于应用程序域)
 Assembly asm2 = Assembly.Load("System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
 ​
 // 3. 从文件加载
 Assembly asm3 = Assembly.LoadFrom(@"C:\MyLibs\MyLibrary.dll");
 ​
 // 4. 获取入口程序集
 Assembly entryAsm = Assembly.GetEntryAssembly();

1.2 通过类型获取

csharp

复制代码
 Assembly asm4 = typeof(MyClass).Assembly;

2. 常用属性

属性 说明
FullName 程序集完整显示名称(包含名称、版本、区域、公钥令牌)。
Location 程序集文件在磁盘上的物理路径(若已加载)。
CodeBase 程序集的原始 URI 位置(已过时,建议用 Location)。
ImageRuntimeVersion 程序集生成时使用的 CLR 版本(如 v4.0.30319)。
EntryPoint 返回程序集入口方法(如 Main 方法),若无则返回 null。
IsDynamic 指示程序集是否通过反射发出(Reflection.Emit)动态生成。

csharp

复制代码
 Console.WriteLine(asm1.FullName);           // "MyApp, Version=1.0.0.0,        Culture=neutral, PublicKeyToken=null"
 Console.WriteLine(asm1.Location);           // "C:\MyApp\bin\Debug\MyApp.exe"
 Console.WriteLine(asm1.ImageRuntimeVersion);// "v4.0.30319"

3. 常用方法

3.1 类型反射

方法 说明
GetTypes() 获取程序集中定义的所有公共类型。
GetExportedTypes() 获取程序集中定义的公共类型(可被外部访问)。
GetType(string name) 通过类型全名获取 Type 对象。
GetReferencedAssemblies() 获取当前程序集引用的所有程序集名称(AssemblyName)。
复制代码
 Type[] allTypes = asm1.GetTypes();
 foreach (Type t in allTypes)
 {
     Console.WriteLine(t.FullName);
 }
 ​
 Type myType = asm1.GetType("MyNamespace.MyClass");

3.2 动态创建实例

方法 说明
CreateInstance(string typeName) 创建指定类型(区分大小写)的实例,返回 object。
CreateInstance(string typeName, bool ignoreCase) 是否忽略大小写。
CreateInstance(string typeName, bool ignoreCase, BindingFlags binder, object\[\] args, CultureInfo culture) 完整重载,支持参数传递。
复制代码
 // 创建无参实例
 object obj = asm1.CreateInstance("MyNamespace.MyClass");
 ​
 // 创建带参数的实例
 object obj2 = asm1.CreateInstance(
     "MyNamespace.MyClass", 
     false, 
     BindingFlags.Default, 
     null, 
     new object[] { 42, "hello" }, 
     null, 
     null);

3.3 读取自定义特性

方法 说明
GetCustomAttributes() 获取程序集上定义的所有自定义特性。
GetCustomAttributes(Type attributeType) 获取指定类型的特性。
GetCustomAttributesData() 获取特性数据(不创建实例,适用于仅反射场景)。
复制代码
 // 获取程序集的 AssemblyTitle 特性
 var titleAttr = asm1.GetCustomAttribute<AssemblyTitleAttribute>();
 Console.WriteLine(titleAttr?.Title);

3.4 访问嵌入资源

方法 说明
GetManifestResourceNames() 获取程序集中所有嵌入资源的名称。
GetManifestResourceStream(string name) 获取嵌入资源的数据流(Stream)。
GetManifestResourceInfo(string name) 获取资源的位置等信息。

csharp

复制代码
 // 列出所有嵌入资源
 string[] resources = asm1.GetManifestResourceNames();    //获取程序集中所有嵌入资源的名称
 foreach (string res in resources)
 {
     Console.WriteLine(res);
 }
 ​
 // 读取文本资源
 using (Stream stream = asm1.GetManifestResourceStream("MyApp.Resources.Config.xml"))
 using (StreamReader reader = new StreamReader(stream))
 {
     string content = reader.ReadToEnd();
 }

注意 :资源名称通常是命名空间.文件夹名.文件名,需准确指定。

3.5 安全性

方法 说明
Evidence 获取程序集的证据(用于安全策略,已过时)。
PermissionSet 获取程序集所需的权限集。

4. 完整示例:加载外部程序集并调用方法

复制代码
 using System;
 using System.Reflection;
 ​
 public class Program
 {
     public static void Main()
     {
         // 1. 从文件加载程序集
         Assembly pluginAsm = Assembly.LoadFrom(@"C:\Plugins\Calculator.dll");
 ​
         // 2. 获取类型
         Type calcType = pluginAsm.GetType("CalculatorLib.Calculator");
         if (calcType == null)
         {
             Console.WriteLine("类型未找到");
             return;
         }
 ​
         // 3. 创建实例
         object calculator = Activator.CreateInstance(calcType);
         // 或使用 assembly.CreateInstance:
         // object calculator = pluginAsm.CreateInstance("CalculatorLib.Calculator");
 ​
         // 4. 调用方法
         MethodInfo addMethod = calcType.GetMethod("Add", new Type[] { typeof(int), typeof(int) });
         int result = (int)addMethod.Invoke(calculator, new object[] { 3, 5 });
         Console.WriteLine($"3 + 5 = {result}");
 ​
         // 5. 读取程序集特性
         var versionAttr = pluginAsm.GetCustomAttribute<AssemblyFileVersionAttribute>();
         Console.WriteLine($"插件版本: {versionAttr?.Version}");
     }
 }

5. 注意事项

  1. 性能 :反射(特别是 Invoke)比直接调用慢得多,应避免在性能敏感的循环中使用。

  2. 依赖项 :使用 LoadFrom 时,CLR 会尝试加载依赖程序集(从相同目录或全局程序集缓存)。如果依赖项不在预期位置,会引发 FileNotFoundException。

  3. 多个上下文 :Load 与 LoadFrom 将程序集加载到不同的上下文,可能导致同一程序集被加载两次。

  4. 安全性 :从不受信任的源加载程序集存在安全风险(可执行任意代码),建议使用 AssemblyLoadContext(.NET Core 3+)隔离。

  5. 动态程序集 :AssemblyBuilder 生成的动态程序集无法保存到文件(除非指定了 RunAndSave 或 Save)。

  6. .NET Core/.NET 5+ 变更:

    • Assembly.CodeBase 和 Assembly.EscapedCodeBase 已过时,改用 Assembly.Location。

    • Assembly.LoadFile 在 .NET Core 中行为不同(直接加载,无依赖解析)。

    • 推荐使用 AssemblyLoadContext 进行高级程序集加载控制。

6. 总结

Assembly 类是 .NET 反射机制的核心入口之一。掌握它,你就能动态地探索和操作程序集,实现插件系统、依赖注入、模块化设计、资源提取等功能。关键要理解如何获取程序集对象、查询元数据、创建实例和访问嵌入资源,同时注意性能和安全陷阱。

通过 Assembly 类,你几乎可以获取关于程序集的一切信息,是 .NET 高级编程的必备技能。

代码文件"与"运行进程"**的关系:

属性 定义 现场实操中的含义
Assembly.GetExecutingAssembly().Location 当前代码程序集(.dll 或 .exe)所在的磁盘绝对路径。 它是静态的"家"。你通过哪个文件启动,它就指哪里。
currentProcess.MainModule.FileName 当前操作系统进程对应的可执行文件路径。 它是动态的"身份证明"。Windows 记录了这个进程是从哪个 .exe 运行起来的。
相关推荐
程序猿乐锅4 小时前
【从0-1学习Python | 第七篇】Python 面向对象基础
开发语言·笔记·后端·python·学习·1024程序员节
Wang's Blog4 小时前
Java 项目实战: 交友项目 - 查询圈子个人动态:查询我的动态需求分析
java·开发语言·交友
凯瑟琳.奥古斯特4 小时前
力扣1016高效解法:剪枝优化技巧
开发语言·c++·算法·leetcode·职场和发展
坤坤子吖5 小时前
C++继承:友元、静态成员、多继承与组合
开发语言·c++·笔记·学习·1024程序员节
技术小甜甜5 小时前
【Cursor】Skill 被标黄色警告,怎么改成合格的 SKILL.md
开发语言·javascript·ai编程·cursor·1024程序员节·ai agent·skills
小小龙学IT6 小时前
Python Polars 高性能数据处理引擎深度解析
开发语言·python·rust·1024程序员节
quantdash_cc6 小时前
如何利用标的信息为研究股票池补充名称和交易所信息?
开发语言·python·pandas·量化交易·1024程序员节·股票数据·quantdash
CRMEB系统商城7 小时前
家电零售的供应商协同与物流提效
java·开发语言·人工智能·小程序·1024程序员节
王大师王文峰7 小时前
Java+AI 面试题(二):业务场景设计 10 例【客服机器人、合同审查、Text2SQL、告警降噪、成本优化】场景题答法与追问链路
java·开发语言·人工智能
言乐67 小时前
Python实现三轴联动根据数据自动打磨镜片模型
开发语言·python