反射和特性
- 人工智能
- 2025-09-02 17:33:02

反射(Reflection)
反射是C#中强大的机制,允许程序在运行时动态获取类型信息、操作对象或调用方法,而无需在编译时明确直到类型的定义。
动态类型操作
通过Type类获取类型信息(如typeof()或obj.GetType()),检查继承关系(IsSubclassOf)、接口实现(IsAssignableFrom)等。
动态创建实例:Activator.CreateInstance支持通过构造函数参数甚至私有构造方法实例化对象。
调用方法和属性:通过MethodInfo.Invoke执行方法,PropertyInfo.SetValue设置属性值。
处理泛型:例如通过MakeGenericType创建泛型类实例,MakeGenericMethod调用泛型方法。
程序集操作
加载外部程序集:Assembly.LoadFrom或Assembly.LoadFile动态加载DLL。
遍历程序集的类型和成员:例如获取所有公共方法或私有字段。
性能与限制
反射虽灵活,但存在性能开销(因动态解析类型)和安全性风险(如访问私有成员破坏封装)。
适用场景:序列化、依赖注入、测试框架等需要动态行为的场景
使用方法获取类型信息
通过Type类获取对象的类型元数据
Type type = typeof(int); // 通过类型名 Type type2 = myObj.GetType(); // 通过对象实例动态创建对象
使用Activator.CreateInstance创建实例
Type type = typeof(MyClass); object instance = Activator.CreateInstance(type); 访问成员获取属性、方法、字段信息
PropertyInfo[] props = type.GetProperties(); MethodInfo method = type.GetMethod("MyMethod"); 动态调用方法通过反射调用方法
MethodInfo method = type.GetMethod("Add"); int result = (int)method.Invoke(instance, new object[] { 2, 3 }); 汇总使用场景插件系统:动态加载程序集(DLL)并调用其功能。
序列化/反序列化:通过反射便利对象的属性生成JSON/XML。
ORM框架:将数据库记录映射到对象属性。
单元测试框架:自动发现并执行测试方法。
注意要点反射操作通常比静态代码慢,需要慎重使用。
缓存Type或MethodInfo对象。
使用dynamic关键字(动态类型)。
改用表达树(Expression Trees)或源代码生成器(Souree Generators)。
反射官方文档属性和反射 - C# | Microsoft Learn
特性(Attributes)特性是为代码元素(类、方法、属性等)添加元数据的标记,这些元数据可通过反射在运行时读取,用于控制程序行为或提供额外信息。
内置常用类型[AttributeUsage] 约束自定义特性的应用目标(如类、方法)和是否允许多次应用。
[Obsolete] 标记方法或类已过时。
[Obsolete("Use NewMethod instead", error: true)] public void OldMethod() { }[Serializable] 标记类可序列化。
[DllImport] 用于调用非托管代码。
[Conditional] 条件编译(如调试代码): [Conditional("DEBUG")] public void Log(string message) { } 自定义特性 自定特性类 继承Attribute类并添加元数据 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)] public class AuthorAttribute : Attribute { public string Name { get; } public AuthorAttribute(string name) => Name = name; }应用特性 将特性标记到目标代码元素
[Author("John")] [Author("Jane", Version = 2.0)] // 允许通过属性传递参数 public class MyClass { } 通过反射读取特性 在运行时获取特性信息 Type type = typeof(MyClass); var attributes = type.GetCustomAttributes(typeof(AuthorAttribute), false); foreach (AuthorAttribute attr in attributes) { Console.WriteLine($"作者: {attr.Name}"); } 汇总使用场景验证逻辑:通过特性标记必填字段(类似[Required])。
Web路由:ASP.NET Core中[HttpGet]、[Route]等特性定义API端点。
权限控制:自定义[Authorize]特性限制访问权限。
文档生成:为Swagger等工具提供API描述信息([ApiExplorer])。
特性官方文档属性和反射 - C# | Microsoft Learn
反射与特性的协同两者结合可实现高度动态化的编程模式:
元数据驱动设计
特性提供结构化元数据(如[Required]验证标记),反射在运行时读取并执行逻辑(如自动验证字段)。
示例:ASP.NET MVC通过[HttpGet]等特性标记控制器方法,反射解析路由并调用对应方法。
动态代码生成与扩展
反射可动态生成类型(如Emit技术),特性则为生成的代码添加配置信息。
序列化库(如JSON.NET )利用特性控制序列化行为(如[JsonPropertyName]),反射遍历属性进行转换。
反射和特性优缺特点 技术优点缺点反射动态性高、支持通用代码(如插件系统)性能低、破坏封装、代码可读性差特性声明式编程、简化配置、增强元数据过度使用导致维护困难、兼容性依赖运行时版本 反射和特性使用方面 自动注册服务:通过扫描程序集中标记了`[Service]`特性的类,实现依赖注入。AOP(面向切面编程):通过特性标记需要拦截的方法,利用反射动态生成代理。 // 自定义特性标记Excel列索引 [AttributeUsage(AttributeTargets.Property)] public class ExcelColumnAttribute : Attribute { public int Index { get; } public ExcelColumnAttribute(int index) => Index = index; } public class Product { [ExcelColumn(0)] public string Name { get; set; } [ExcelColumn(1)] public decimal Price { get; set; } } // 反射读取特性并映射Excel数据 public static List<Product> ParseExcel(string filePath) { var products = new List<Product>(); var type = typeof(Product); foreach (var prop in type.GetProperties()) { var attr = prop.GetCustomAttribute<ExcelColumnAttribute>(); if (attr != null) { // 根据attr.Index读取Excel列并赋值 } } return products; } 反射和特性注意事项安全性:反射可能绕过访问修饰符(如访问私有成员),需谨慎使用。
维护性:过度依赖反射会降低代码可读性,尽量通过接口或泛型替代。
性能敏感场景:避免在频繁执行的代码路径中使用反射。