反射(Reflection) vs 动态(dynamic)
1. 反射 vs 动态
✅ 概念区别:
| 项目 | 反射(Reflection) | dynamic |
|---|---|---|
| 类型检查 | 编译时已知(静态类型) | 编译时未知,运行时决定 |
| 成员调用 | 需使用 MethodInfo 等 | 直接使用对象成员语法 |
| 语法复杂度 | 较高,需了解 API | 更自然,易书写 |
| 性能 | 慢(元数据解析) | 慢(动态调度) |
| 应用场景 | 框架、元数据操作 | COM 互操作、ExpandoObject、简单动态调用 |
✅ 示例:
反射方式调用方法:
var method = typeof(Person).GetMethod("SayHello");
method.Invoke(personObj, null);
dynamic 方式调用方法:
dynamic obj = personObj;
obj.SayHello(); // 编译时不检查
✅ 关键点总结:
dynamic使用简单,适合逻辑不复杂的场景Reflection功能强大,适合写框架、深入操作元数据
2. 如何优化反射性能?
反射性能差的核心原因是 频繁使用元数据解析(如 GetMethod())和运行时调度(如 Invoke())。
✅ 优化技巧:
① 缓存反射信息(Type、MethodInfo)
private static Dictionary<string, MethodInfo> _cache = new();
MethodInfo method = _cache.GetOrAdd("Person.SayHello", () =>
typeof(Person).GetMethod("SayHello"));
② 使用委托替代 Invoke()
var method = typeof(Person).GetMethod("SayHello");
var del = (Action<Person>)Delegate.CreateDelegate(typeof(Action<Person>), null, method);
del(new Person());
③ 使用表达式树(Expression Tree)
ParameterExpression param = Expression.Parameter(typeof(Person), "p");
MethodCallExpression call = Expression.Call(param, "SayHello", null);
var lambda = Expression.Lambda<Action<Person>>(call, param).Compile();
lambda(new Person());
性能对比(大致):
普通方法调用 ≫ 委托 ≫ 表达式树 ≫ 反射Invoke
3. 反射结合 Attribute 构建数据验证器
✅ 场景:你为实体类加上 Attribute,然后通过反射读取这些特性进行数据校验。
示例:定义验证特性
[AttributeUsage(AttributeTargets.Property)]
public class RequiredAttribute : Attribute
{
public string ErrorMessage { get; set; } = "不能为空";
}
示例:实体类
public class User
{
[Required(ErrorMessage = "用户名不能为空")]
public string Username { get; set; }
public int Age { get; set; }
}
示例:反射读取验证逻辑
public class Validator
{
public static List<string> Validate(object obj)
{
List<string> errors = new();
var props = obj.GetType().GetProperties();
foreach (var prop in props)
{
var attr = prop.GetCustomAttribute<RequiredAttribute>();
if (attr != null)
{
var value = prop.GetValue(obj);
if (value == null || string.IsNullOrWhiteSpace(value.ToString()))
errors.Add(attr.ErrorMessage);
}
}
return errors;
}
}
使用:
var user = new User();
var errors = Validator.Validate(user);
foreach (var error in errors)
Console.WriteLine(error);
📌 这个思路可用于构建自定义表单验证器、DTO 检查器等框架。
4. 使用 Assembly.Load 实现插件机制
反射的高级应用 —— 动态加载 DLL 并调用类和方法,构建“插件系统”。
✅ 步骤 1:定义插件接口
public interface IPlugin
{
string Name { get; }
void Run();
}
✅ 步骤 2:编写插件 DLL 工程(如 MyPlugin.dll)
public class HelloPlugin : IPlugin
{
public string Name => "Hello Plugin";
public void Run() => Console.WriteLine("Hello from plugin!");
}
✅ 步骤 3:主程序中动态加载 DLL
string pluginPath = "MyPlugin.dll";
Assembly asm = Assembly.LoadFrom(pluginPath);
var pluginTypes = asm.GetTypes()
.Where(t => typeof(IPlugin).IsAssignableFrom(t) && !t.IsInterface);
foreach (var type in pluginTypes)
{
var plugin = (IPlugin)Activator.CreateInstance(type);
Console.WriteLine($"[加载插件] {plugin.Name}");
plugin.Run();
}
✅ 应用场景:
- 脚本扩展机制(如游戏模组、IDE 插件)
- 企业级业务组件热插拔
- 框架级别的动态扩展(类似 ASP.NET Core 的中间件)
权威资料参考
总结:一句话核心记忆
dynamic用于动态类型的简单调用Reflection是构建框架/插件/元数据操作的必备利器- 性能关键在于缓存与委托替代
- 特性 + 反射 = 构建“可配置、可扩展”的业务逻辑基石
Assembly.Load是实现松耦合插件化架构的入口
更多详细内容请关注其他相关文章!