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. 多个上下文LoadLoadFrom 将程序集加载到不同的上下文,可能导致同一程序集被加载两次。

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

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

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

    • Assembly.CodeBaseAssembly.EscapedCodeBase 已过时,改用 Assembly.Location

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

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

6. 总结

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

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

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

属性 定义 现场实操中的含义
Assembly.GetExecutingAssembly().Location 当前代码程序集(.dll 或 .exe)所在的磁盘绝对路径。 它是静态的"家"。你通过哪个文件启动,它就指哪里。
currentProcess.MainModule.FileName 当前操作系统进程对应的可执行文件路径。 它是动态的"身份证明"。Windows 记录了这个进程是从哪个 .exe 运行起来的。
相关推荐
少控科技2 小时前
C#基础训练营 - 02 - 运算器
开发语言·c#
Riemann~~3 小时前
C语言嵌入式风格
c语言·开发语言
zmzb01034 小时前
C++课后习题训练记录Day104
开发语言·c++
zmzb01035 小时前
C++课后习题训练记录Day105
开发语言·c++·算法
wjs20245 小时前
Vue3 条件语句
开发语言
_codemonster5 小时前
JavaWeb开发系列(六)JSP基础
java·开发语言
Web打印6 小时前
Phpask(php集成环境)之16 怎样彻底停用一个网站
开发语言·php
临水逸6 小时前
飞牛fnos 2025 漏洞Java跨域URL浏览器
java·开发语言·安全·web安全
H Corey6 小时前
数据结构与算法:高效编程的核心
java·开发语言·数据结构·算法