assembly 类位于 system.reflection 命名空间,表示一个可重用、可部署且可版本化的 .net 程序集。程序集是 .net 应用程序的基本构建块,包含了类型、资源、元数据和清单。
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 通过类型获取
assembly asm4 = typeof(myclass).assembly;
2. 常用属性
| 属性 | 说明 |
|---|
| fullname | 程序集完整显示名称(包含名称、版本、区域、公钥令牌)。 |
| location | 程序集文件在磁盘上的物理路径(若已加载)。 |
| codebase | 程序集的原始 uri 位置(已过时,建议用 location)。 |
| imageruntimeversion | 程序集生成时使用的 clr 版本(如 v4.0.30319)。 |
| entrypoint | 返回程序集入口方法(如 main 方法),若无则返回 null。 |
| isdynamic | 指示程序集是否通过反射发出(reflection.emit)动态生成。 |
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) | 获取资源的位置等信息。 |
// 列出所有嵌入资源
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. 注意事项
- 性能:反射(特别是 invoke)比直接调用慢得多,应避免在性能敏感的循环中使用。
- 依赖项:使用 loadfrom 时,clr 会尝试加载依赖程序集(从相同目录或全局程序集缓存)。如果依赖项不在预期位置,会引发 filenotfoundexception。
- 多个上下文:load 与 loadfrom 将程序集加载到不同的上下文,可能导致同一程序集被加载两次。
- 安全性:从不受信任的源加载程序集存在安全风险(可执行任意代码),建议使用 assemblyloadcontext(.net core 3+)隔离。
- 动态程序集:assemblybuilder 生成的动态程序集无法保存到文件(除非指定了 runandsave 或 save)。
- .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 运行起来的。 |
到此这篇关于c#中assembly类的使用小结的文章就介绍到这了,更多相关c# assembly类内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论