C#中的Reflection反射

生成模型:QwQ-32B,生成时间:2025 03-18 20:50

在 C# 中,Reflection(反射) 是一种 运行时检查和操作程序集、类型、方法、属性等元数据 的机制。它允许程序在运行时动态获取对象的信息(如类型、方法、字段)、创建对象、调用方法,甚至修改对象的状态。反射是 C# 中实现 动态编程 的核心工具之一。

反射的核心概念

反射的核心是通过 System.Type 类来表示类型信息,并通过该类的成员(如 GetMethods()GetProperties() 等)获取类型的所有成员(方法、属性、字段等)。

反射的主要用途

  1. 动态类型检查:在运行时获取对象的类型信息。
  2. 动态创建对象:根据类型名称创建对象实例。
  3. 动态调用方法:在运行时调用对象的方法。
  4. 动态访问属性/字段:读取或修改对象的属性或字段值。
  5. 插件系统:通过加载外部程序集(DLL)动态扩展功能。

反射的基本步骤

步骤 1:获取类型信息

通过以下方式获取 Type 对象:

  • 直接通过类型名:typeof(类型)
  • 通过对象实例:object.GetType()
  • 通过程序集加载类型:assembly.GetType("全名")

步骤 2:操作类型信息

  • 获取方法、属性、字段等。
  • 创建对象实例。
  • 调用方法或访问成员。

示例代码

以下是一个完整的示例,演示如何通过反射动态创建对象、调用方法、访问属性:

定义一个测试类

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }

    public Person(string name, int age)
    {
        Name = name;
        Age = age;
    }

    public void SayHello()
    {
        Console.WriteLine($"Hello, my name is {Name}, I'm {Age} years old.");
    }
}

使用反射操作该类

using System;
using System.Reflection;

public class Program
{
    public static void Main()
    {
        // 步骤1:获取Person类型的Type对象
        Type personType = typeof(Person);

        // 步骤2:创建Person对象实例(通过构造函数)
        ConstructorInfo constructor = personType.GetConstructor(new Type[] { typeof(string), typeof(int) });
        object personInstance = constructor.Invoke(new object[] { "Alice", 30 });

        // 步骤3:调用实例方法SayHello()
        MethodInfo method = personType.GetMethod("SayHello");
        method.Invoke(personInstance, null); // 输出:Hello, my name is Alice, I'm 30 years old.

        // 步骤4:访问属性Name和Age
        PropertyInfo nameProperty = personType.GetProperty("Name");
        PropertyInfo ageProperty = personType.GetProperty("Age");

        Console.WriteLine($"Name: {nameProperty.GetValue(personInstance)}"); // Alice
        Console.WriteLine($"Age: {ageProperty.GetValue(personInstance)}");   // 30

        // 步骤5:修改属性值
        nameProperty.SetValue(personInstance, "Bob");
        ageProperty.SetValue(personInstance, 25);

        // 再次调用方法查看修改后的值
        method.Invoke(personInstance, null); // 输出:Hello, my name is Bob, I'm 25 years old.
    }
}

关键方法和类

核心类

  1. Type :表示类型信息。
    • GetMethods():获取类型的所有方法。
    • GetProperties():获取类型的所有属性。
    • GetFields():获取类型的所有字段。
    • GetConstructor():获取构造函数。
  2. Assembly :表示程序集(如 DLL 或 EXE)。
    • Assembly.Load():加载程序集。
    • GetTypes():获取程序集中的所有类型。
  3. MethodInfoPropertyInfoFieldInfo:分别表示方法、属性、字段的信息。

常用方法

  • 创建对象
    object instance = Activator.CreateInstance(type, parameters); // 调用构造函数
    
  • 调用方法
    MethodInfo method = type.GetMethod("MethodName");
    method.Invoke(instance, parameters);
    
  • 访问属性
    PropertyInfo property = type.GetProperty("PropertyName");
    object value = property.GetValue(instance);
    property.SetValue(instance, newValue);
    

典型应用场景

场景1:动态加载插件

// 加载外部程序集并创建类型实例
Assembly pluginAssembly = Assembly.LoadFrom("Plugin.dll");
Type pluginType = pluginAssembly.GetType("Plugin.PluginClass");
object pluginInstance = Activator.CreateInstance(pluginType);

场景2:序列化/反序列化

反射常用于框架(如 JSON 序列化)中,动态获取对象的属性并转换为其他格式。

场景3:依赖注入

通过反射创建对象并注入依赖项。

注意事项

  1. 性能开销:反射操作通常比直接代码调用慢,需避免在性能敏感的代码中频繁使用。
  2. 安全性:反射可以访问私有成员,需注意代码的安全性。
  3. 异常处理:使用反射时需处理可能的 NullReferenceException(如找不到方法或属性)。

示例代码总结

上述示例演示了以下反射操作:

  1. 通过 typeof() 获取类型。
  2. 通过构造函数创建对象。
  3. 动态调用方法和访问属性。
  4. 修改属性值并验证结果。

扩展阅读

  • System.Reflection.Emit:通过反射动态生成代码(如编译IL代码)。
  • dynamic 关键字:C# 4.0 引入的动态类型,底层依赖反射。

通过反射,可以实现高度灵活的代码逻辑,但需权衡性能和复杂度。