反射(Reflection) vs 动态(dynamic)
                           
天天向上
发布: 2025-04-19 09:55:45

原创
821 人浏览过

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 是实现松耦合插件化架构的入口

更多详细内容请关注其他相关文章!

发表回复 0

Your email address will not be published. Required fields are marked *