C# 反射(Reflection)

`Type`、动态创建与调用、属性读写、以及性能代价。

Advanced
Key Points反射让程序在运行时检查并操作类型,代价是比直接调用慢 10~100 倍。

获取 Type

C#
using System;
using System.Reflection;

var t1 = typeof(string);
var t2 = "abc".GetType();
var t3 = Type.GetType("System.String");

Console.WriteLine(t1 == t2);
Console.WriteLine(t1.Name);
Console.WriteLine(t1.FullName);
Console.WriteLine(t1.IsClass);
Console.WriteLine(t1.IsValueType);
Console.WriteLine(typeof(int).IsValueType);
Output
True
String
System.String
True
False
True

查看成员

C#
using System;
using System.Linq;
using System.Reflection;

var t = typeof(List<int>);

Console.WriteLine(t.Name);

foreach (var ctor in t.GetConstructors())
{
    Console.WriteLine("构造:" + string.Join(",", ctor.GetParameters().Select(p => p.ParameterType.Name)));
}

foreach (var m in t.GetMethods(BindingFlags.Public | BindingFlags.Instance).Take(5))
{
    Console.WriteLine($"方法 {m.Name} -> {m.ReturnType.Name}");
}

foreach (var p in t.GetProperties())
{
    Console.WriteLine($"属性 {p.Name} : {p.PropertyType.Name}");
}
Output
List`1
构造:
构造:Int32
构造:IEnumerable`1
方法 Add -> Void
方法 AddRange -> Void
方法 Insert -> Void
方法 InsertRange -> Void
方法 RemoveAt -> Void
属性 Capacity : Int32
属性 Count : Int32
属性 Item : Int32

动态创建与调用

C#
using System;
using System.Reflection;

var t = Type.GetType("System.Text.StringBuilder")!;
var sb = Activator.CreateInstance(t)!;

var append = t.GetMethod("Append", new[] { typeof(string) })!;
append.Invoke(sb, new object[] { "Hello" });
append.Invoke(sb, new object[] { ", World" });

var toString = t.GetMethod("ToString", Type.EmptyTypes)!;
Console.WriteLine(toString.Invoke(sb, null));
Output
Hello, World

Activator.CreateInstance builds the object, GetMethod finds the method and Invoke calls it. Pass the parameter type array to GetMethod or overloads throw AmbiguousMatchException.

读写属性

C#
using System;
using System.Reflection;

class User
{
    public string Name { get; set; } = "张三";
    public int Age { get; set; } = 28;
    private string Secret { get; set; } = "hidden";
}

var u = new User();
var t = typeof(User);

foreach (var p in t.GetProperties())
{
    var v = p.GetValue(u);
    Console.WriteLine($"{p.Name} = {v}");
}

t.GetProperty("Age")!.SetValue(u, 30);
Console.WriteLine(u.Age);

// 私有成员也能读(需要 BindingFlags)
var secret = t.GetProperty("Secret", BindingFlags.NonPublic | BindingFlags.Instance);
Console.WriteLine(secret?.GetValue(u));
Output
Name = 张三
Age = 28
30
hidden
Reflection reaches private members, bypassing encapsulation. Acceptable in tests to stub internal state; in production it signals a design problem — add a proper API instead.

性能代价

C#
using System;
using System.Diagnostics;
using System.Reflection;

class Target { public int Add(int a, int b) => a + b; }

var obj = new Target();
var method = typeof(Target).GetMethod("Add")!;
var args = new object[] { 1, 2 };

var sw = Stopwatch.StartNew();
for (int i = 0; i < 1_000_000; i++) obj.Add(1, 2);
var direct = sw.ElapsedMilliseconds;

sw.Restart();
for (int i = 0; i < 1_000_000; i++) method.Invoke(obj, args);
var reflect = sw.ElapsedMilliseconds;

Console.WriteLine($"直接 {direct}ms 反射 {reflect}ms 倍数 {reflect / Math.Max(1, direct)}");
Output
直接 2ms 反射 187ms 倍数 93
ApproachSpeedUse
直接调用1x默认
反射 Invoke~50-100x 慢启动时一次性的装配
缓存 MethodInfo略好避免重复查找
编译表达式树~2x 慢需要高频调用
dynamic~10x 慢脚本、简单动态
源生成器1x编译期生成代码

什么时候用反射

  • 该用 —— 序列化框架(JSON/XML)、ORM、依赖注入容器、插件系统
  • 该用 —— 单元测试里构造内部状态
  • 不该用 —— 业务代码里按字符串调方法(用接口或委托)
  • 不该用 —— 热路径(每秒上万次),除非缓存了委托
Modern .NET prefers source generators over runtime reflection: code is generated at build time with no startup cost and no AOT trimming issues. System.Text.Json's JsonSerializerContext is exactly this.

Friends & Partners