跳转到内容

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#应用程序。