C# Assembly
内容提要
Assembly是.NET框架的基本构建模块,用于封装代码和资源,并支持版本控制、安全性、类型信息、可再分发性和依赖管理。私有Assembly仅供单个应用程序使用,共享Assembly可以被多个应用程序使用。GAC是全局程序集缓存,用于存储共享Assembly。Assembly和AppDomain是不同的概念,Assembly是基本构建单元,用于模块化和重用,而AppDomain是应用程序的执行环境,提供隔离和管理。CLR不提供卸载单独程序集的能力,因为会导致应用程序崩溃,可以通过卸载整个AppDomain来释放相关的程序集和资源。反射的缺点包括类型安全性不确定、速度慢和性能影响,应避免使用反射来访问字段或调用方法/属性。
延伸解读
Assembly 与 AppDomain:物理单元与逻辑环境的区分
Assembly 是代码和资源的物理单位,以 DLL 或 EXE 形式存在,承载类型信息和版本控制;AppDomain 是逻辑执行环境,提供进程内隔离。Assembly 加载后共享到 AppDomain 中,而 AppDomain 用于隔离和管理执行。理解这一区别有助于在模块化设计和运行时隔离之间做出正确选择。
为何 CLR 不支持卸载单个程序集
CLR 不提供卸载单独程序集的能力,因为一旦线程返回到已卸载程序集中的代码,应用程序就会崩溃。即使通过 ReflectionOnlyLoadFrom 加载的程序集表面可卸载,CLR 也不允许,因为仍可能通过反射创建对象引用其元数据。卸载程序集必须卸载整个 AppDomain,这是为了确保应用程序的稳定性和安全性。
反射的性能代价与替代方案
反射依赖字符串进行类型和成员查找,丧失编译时类型安全性,且运行时字符串搜索和参数打包解包会显著影响性能。示例中直接调用百万次仅需 1 毫秒,反射调用则需 10 毫秒。建议避免用反射访问字段或调用方法,可让类型从已知基类派生或实现已知接口,在运行时构造实例并通过基类或接口调用。
AppDomain.Load 的潜在风险与使用建议
AppDomain.Load 是实例方法,设计由非托管代码调用,用于将程序集注入指定 AppDomain。托管代码一般不应调用,因为程序集对象需按值封送回发出调用的 AppDomain,CLR 会使用发出调用方的策略和搜索位置重新加载,可能导致 FileNotFoundException 或加载非预期文件。应优先使用 Assembly.Load 进行动态加载。
Q&A
Assembly在.NET框架中有什么作用?
Assembly是.NET框架的基本构建模块,封装代码和资源,支持版本控制、安全性、类型信息、可再分发性和依赖管理。
私有Assembly和共享Assembly有什么区别?
私有Assembly仅供单个应用程序使用,通常存放在应用程序目录中;共享Assembly可以被多个应用程序使用,通常存放在全局程序集缓存(GAC)中。
全局程序集缓存(GAC)有什么重要特点?
GAC允许多个应用程序共享使用公共的Assembly,支持不同版本的共存,并且只有具有强名称签名的Assembly才能存放在GAC中。
Assembly和AppDomain之间的区别是什么?
Assembly是代码和资源的物理单位,而AppDomain是逻辑的执行环境,AppDomain提供应用程序的隔离和管理。
为什么CLR不支持卸载单独的程序集?
CLR不支持卸载单独程序集是为了确保应用程序的稳定性和安全性,卸载单个程序集可能导致内存管理复杂性和应用程序崩溃。
反射在C#中有哪些缺点?
反射的缺点包括类型安全性不确定、速度慢和性能影响,建议避免使用反射来访问字段或调用方法/属性。