什么是C#中的反射
在C#开发中,反射(Reflection)是一种强大的机制,它允许程序在运行时查看和使用自身类型的信息。比如你写了一个类,但不想在代码里“硬编码”调用它,而是希望程序自己去“发现”这个类并执行方法,这时候反射就派上用场了。
想象一下你在做一个插件系统,主程序不知道插件的具体实现,但插件加载后能自动注册功能。这种“动态加载、动态调用”的能力,正是反射的核心价值。
从Type入手:获取类型信息
每个类型在运行时都有一个对应的System.Type对象。通过它,你能拿到类名、方法、属性等信息。
using System;
public class Calculator {
public int Add(int a, int b) {
return a + b;
}
}
class Program {
static void Main() {
Type type = typeof(Calculator);
Console.WriteLine("类型名称:" + type.Name);
foreach (var method in type.GetMethods()) {
Console.WriteLine("方法:" + method.Name);
}
}
}上面这段代码输出Calculator类的所有公共方法名。你会发现Add方法被列出来了,这就是通过反射查看类型的结构。
创建实例并调用方法
除了查看,反射还能动态创建对象。比如你只知道类名是一个字符串,照样可以new出来。
object instance = Activator.CreateInstance(typeof(Calculator));
var result = type.GetMethod("Add").Invoke(instance, new object[] { 5, 3 });
Console.WriteLine("计算结果:" + result); // 输出 8这里没有直接new Calculator(),而是用CreateInstance创建实例,再通过GetMethod找到方法,最后Invoke传参执行。这在处理配置驱动或用户自定义逻辑时特别有用。
实际应用场景举例
假设你在开发一个媒体处理软件,支持多种格式转换。每种格式对应一个处理类,如Mp4Converter、AviConverter。你可以把这些类都放在一个命名空间下,启动时扫描程序集,自动发现所有转换器并注册到菜单里。
var assembly = Assembly.GetExecutingAssembly();
var converterTypes = assembly.GetTypes()
.Where(t => t.Namespace == "MediaConverters" && t.Name.EndsWith("Converter"));
foreach (var t in converterTypes) {
Console.WriteLine("发现转换器:" + t.Name);
}这样新增一种格式,只要写个新类,不用改主逻辑,系统自动识别。维护起来轻松多了。
访问私有成员?也可以
默认情况下反射只能看到公共成员,但加上BindingFlags就能突破限制。
class SecretClass {
private string GetSecret() => "这是秘密内容";
}
// 反射调用私有方法
var secretType = typeof(SecretClass);
var method = secretType.GetMethod("GetSecret", BindingFlags.NonPublic | BindingFlags.Instance);
var obj = Activator.CreateInstance(secretType);
var msg = method.Invoke(obj, null);
Console.WriteLine(msg);虽然这功能强大,但也得小心使用。滥用反射可能破坏封装性,影响性能,调试也更困难。
小贴士:性能与适用场景
反射不是银弹。每次GetType、GetMethod都是运行时查找,比直接调用慢得多。频繁操作建议缓存Type对象或MethodInfo引用。对于配置化程度高、扩展性强的系统,比如插件架构、ORM框架、序列化工具,反射才是真正的利器。