C Sharp 反射基础
外观
C#反射基础[编辑 | 编辑源代码]
反射(Reflection)是C#中一种强大的机制,允许程序在运行时检查、分析和操作类型、对象及其成员。通过反射,开发者可以动态加载程序集、获取类型信息、调用方法或访问属性,而无需在编译时知道这些细节。反射在插件系统、序列化、依赖注入等场景中广泛应用。
反射的核心概念[编辑 | 编辑源代码]
反射的核心围绕以下几个类展开:
- System.Type:表示类型声明(类、接口、数组等)。
- System.Reflection.Assembly:加载和管理程序集。
- System.Reflection.MethodInfo:描述方法的信息。
- System.Reflection.PropertyInfo:描述属性的信息。
- System.Reflection.FieldInfo:描述字段的信息。
获取类型信息[编辑 | 编辑源代码]
在C#中,可以通过以下方式获取类型信息:
// 通过typeof运算符获取类型
Type type1 = typeof(string);
// 通过对象实例获取类型
string str = "Hello";
Type type2 = str.GetType();
// 通过类型名称获取类型
Type type3 = Type.GetType("System.String");
反射类型成员[编辑 | 编辑源代码]
以下示例展示如何反射类型的成员:
using System;
using System.Reflection;
public class Person
{
public string Name { get; set; }
private int Age { get; set; }
public void Greet() => Console.WriteLine($"Hello, I'm {Name}");
}
class Program
{
static void Main()
{
Type personType = typeof(Person);
// 获取所有公共属性
PropertyInfo[] properties = personType.GetProperties();
Console.WriteLine("Properties:");
foreach (var prop in properties)
Console.WriteLine($"- {prop.Name} ({prop.PropertyType})");
// 获取所有公共方法
MethodInfo[] methods = personType.GetMethods();
Console.WriteLine("\nMethods:");
foreach (var method in methods)
Console.WriteLine($"- {method.Name} ({method.ReturnType})");
}
}
输出:
Properties: - Name (System.String) Methods: - get_Name (System.String) - set_Name (System.Void) - Greet (System.Void) - GetType (System.Type) - ToString (System.String) - Equals (System.Boolean) - GetHashCode (System.Int32)
动态创建对象和调用方法[编辑 | 编辑源代码]
反射允许动态创建对象并调用其方法:
using System;
using System.Reflection;
public class Calculator
{
public int Add(int a, int b) => a + b;
}
class Program
{
static void Main()
{
Type calculatorType = typeof(Calculator);
// 动态创建实例
object calculator = Activator.CreateInstance(calculatorType);
// 获取方法信息
MethodInfo addMethod = calculatorType.GetMethod("Add");
// 调用方法
object result = addMethod.Invoke(calculator, new object[] { 5, 3 });
Console.WriteLine($"5 + 3 = {result}"); // 输出: 5 + 3 = 8
}
}
反射的性能考量[编辑 | 编辑源代码]
反射虽然强大,但需要注意性能问题:
- 反射操作比直接代码调用慢很多
- 频繁使用的反射操作应考虑缓存
- 在性能关键路径上避免使用反射
性能优化示例[编辑 | 编辑源代码]
// 不推荐:每次调用都反射
for (int i = 0; i < 1000; i++)
{
MethodInfo method = typeof(MyClass).GetMethod("MyMethod");
method.Invoke(obj, null);
}
// 推荐:缓存MethodInfo
MethodInfo cachedMethod = typeof(MyClass).GetMethod("MyMethod");
for (int i = 0; i < 1000; i++)
{
cachedMethod.Invoke(obj, null);
}
实际应用案例[编辑 | 编辑源代码]
插件系统[编辑 | 编辑源代码]
反射常用于实现插件架构,动态加载程序集:
// 加载插件程序集
Assembly pluginAssembly = Assembly.LoadFrom("MyPlugin.dll");
// 查找所有实现IPlugin接口的类型
var pluginTypes = pluginAssembly.GetTypes()
.Where(t => typeof(IPlugin).IsAssignableFrom(t) && !t.IsAbstract);
// 创建插件实例并执行
foreach (var type in pluginTypes)
{
IPlugin plugin = (IPlugin)Activator.CreateInstance(type);
plugin.Execute();
}
动态表单生成[编辑 | 编辑源代码]
反射可用于根据对象属性自动生成UI表单:
public void GenerateForm(object obj)
{
Type type = obj.GetType();
foreach (PropertyInfo prop in type.GetProperties())
{
Console.WriteLine($"{prop.Name} ({prop.PropertyType.Name}):");
if (prop.PropertyType == typeof(string))
Console.WriteLine($"<input type='text' name='{prop.Name}' />");
else if (prop.PropertyType == typeof(bool))
Console.WriteLine($"<input type='checkbox' name='{prop.Name}' />");
// 其他类型处理...
}
}
反射与泛型[编辑 | 编辑源代码]
反射也可以处理泛型类型和方法:
// 获取泛型类型定义
Type listType = typeof(List<>);
// 创建具体泛型类型
Type stringListType = listType.MakeGenericType(typeof(string));
// 创建实例
object stringList = Activator.CreateInstance(stringListType);
// 调用Add方法
MethodInfo addMethod = stringListType.GetMethod("Add");
addMethod.Invoke(stringList, new object[] { "Hello" });
反射的限制[编辑 | 编辑源代码]
- 无法反射代码优化(如内联方法)
- 对私有成员的访问需要特殊权限
- 跨平台使用时可能有差异
总结[编辑 | 编辑源代码]
反射是C#中强大的元编程工具,它允许程序在运行时检查和操作类型信息。虽然反射提供了极大的灵活性,但也带来了性能开销和安全考虑。合理使用反射可以创建高度动态和可扩展的应用程序,但在性能关键场景应谨慎使用。
反射的典型应用包括:
- 插件系统
- 序列化/反序列化
- 依赖注入容器
- ORM框架
- 动态代理
通过掌握反射,开发者可以编写更加灵活和强大的C#应用程序。