第八章:C#反射避坑指南:那些年我们踩过的“天劫雷“

各位.NET道友大家好,我是.NET修仙日记的掌门人,今天我们就来聊一聊反射(Reflection) ,那么什么是反射(Reflection)呢?接下来就和我一起来探索.NET修仙界的反射(Reflection)神通……

一、反射神通的核心概念

1.1 什么是反射?

在.NET修真界,反射(Reflection)是程序自我探查、自我修改的无上神通。它允许我们在运行时:

  • 探查类型信息(类、结构体、接口等)

  • 动态创建对象实例

  • 调用方法和访问属性

  • 获取和操作特性(Attributes)

  • 动态生成代码(通过Emit)

反射运行时

反射运行时

1.2 核心装配说明

反射的核心装配位于System.Reflection命名空间,主要包含以下关键类型:

类型说明常用属性/方法
Assembly代表程序集GetTypes(), GetModules()
Module代表模块GetTypes(), GetFields()
Type代表类型GetMethods(), GetProperties()
MethodInfo方法信息Invoke(), ReturnType
PropertyInfo属性信息GetValue(), SetValue()
FieldInfo字段信息GetValue(), SetValue()

2.基础反射操作

2.1 获取类型信息

// 三种获取Type对象的方式
Type t1 = typeof(string);          // 通过typeof运算符
Type t2 = Type.GetType("System.String"); // 通过类型名称
Type t3 = "hello".GetType();       // 通过实例获取

Console.WriteLine($"类型名称:{t1.Name}");
Console.WriteLine($"命名空间:{t1.Namespace}");
Console.WriteLine($"是类吗?{t1.IsClass}");
Console.WriteLine($"基类型:{t1.BaseType}");

2.2 动态创建实例

动态创建实例示意图

动态创建实例示意图

// 创建不同类型的实例
object list = Activator.CreateInstance(typeof(List<string>));
object dt = Activator.CreateInstance(typeof(DateTime), 2023, 1, 1);

// 带参数的构造
Type sbType = typeof(StringBuilder);
StringBuilder sb = (StringBuilder)Activator.CreateInstance(
    sbType, 
    new object[] { "初始值", 100 });

3.高级反射技巧

3.1 方法调用

// 获取并调用方法
Type mathType = typeof(Math);
MethodInfo maxMethod = mathType.GetMethod("Max", 
    new[] { typeof(int), typeof(int) });

int result = (int)maxMethod.Invoke(null, new object[] { 5, 10 });
Console.WriteLine($"最大值:{result}"); // 输出10

3.2 属性操作

属性操作示意图

属性操作示意图

class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

// 反射操作属性
Person p = new Person();
Type personType = typeof(Person);

PropertyInfo nameProp = personType.GetProperty("Name");
nameProp.SetValue(p, "张三");

PropertyInfo ageProp = personType.GetProperty("Age");
ageProp.SetValue(p, 25);

Console.WriteLine($"{p.Name}, {p.Age}岁");

4.特性(Attribute)处理

4.1 自定义特性

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, 
    AllowMultiple = true)]
public class CultivationStageAttribute : Attribute
{
    public string Stage { get; }
    public int RequiredLevel { get; set; }
    
    public CultivationStageAttribute(string stage)
    {
        Stage = stage;
    }
}

4.2 特性探查

特性探查示意图

特性探查示意图

[CultivationStage("金丹期", RequiredLevel = 5)]
public class GoldenCoreTechnique
{
    [CultivationStage("小成")]
    public void Practice() { }
}

// 探查特性
Type techniqueType = typeof(GoldenCoreTechnique);

// 类级别特性
var classAttributes = techniqueType.GetCustomAttributes(
    typeof(CultivationStageAttribute), false);
foreach(CultivationStageAttribute attr in classAttributes)
{
    Console.WriteLine($"修炼阶段:{attr.Stage},要求等级:{attr.RequiredLevel}");
}

// 方法级别特性
MethodInfo method = techniqueType.GetMethod("Practice");
var methodAttributes = method.GetCustomAttributes(
    typeof(CultivationStageAttribute), false);
// ...类似处理

5.性能优化

5.1 性能对比

性能对比示意图

性能对比示意图

5.2 优化策略

策略1:缓存反射对象
private static readonly Type _cachedType = typeof(MyClass);
private static readonly MethodInfo _cachedMethod = _cachedType.GetMethod("MyMethod");
策略2:使用委托
MethodInfo method = typeof(MyClass).GetMethod("MyMethod");
var del = (Func<MyClass, int>)Delegate.CreateDelegate(
    typeof(Func<MyClass, int>), method);

int result = del(myInstance); // 比Invoke快10倍
策略3:表达式树编译
var param = Expression.Parameter(typeof(MyClass));
var call = Expression.Call(param, method);
var lambda = Expression.Lambda<Func<MyClass, int>>(call, param);
var compiled = lambda.Compile(); // 编译成委托

int result = compiled(myInstance); // 接近原生调用性能

6.Emit高级编程

6.1 IL代码生成

IL代码生成

IL代码生成

6.2 动态方法示例

// 创建动态方法
var dynamicMethod = new DynamicMethod(
    "DynamicAdd",                      // 方法名
    typeof(int),                       // 返回类型
    new[] { typeof(int), typeof(int) }, // 参数类型
    typeof(Program).Module);           // 关联模块

// 生成IL代码
var il = dynamicMethod.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);   // 加载第一个参数
il.Emit(OpCodes.Ldarg_1);   // 加载第二个参数
il.Emit(OpCodes.Add);       // 执行加法
il.Emit(OpCodes.Ret);       // 返回结果

// 创建并调用委托
var addDel = (Func<int, int, int>)dynamicMethod.CreateDelegate(
    typeof(Func<int, int, int>));

int sum = addDel(5, 7); // 输出12

7.实战应用

7.1 插件系统实现

public interface IPlugin
{
    string Name { get; }
    void Execute();
}

public class PluginLoader
{
    public List<IPlugin> LoadPlugins(string path)
    {
        var plugins = new List<IPlugin>();
        
        foreach(string dll in Directory.GetFiles(path, "*.dll"))
        {
            Assembly assembly = Assembly.LoadFrom(dll);
            
            foreach(Type type in assembly.GetTypes())
            {
                if(typeof(IPlugin).IsAssignableFrom(type) && !type.IsAbstract)
                {
                    IPlugin plugin = (IPlugin)Activator.CreateInstance(type);
                    plugins.Add(plugin);
                }
            }
        }
        
        return plugins;
    }
}

7.2 ORM框架示例

public class EntityMapper<T> where T : new()
{
    public T Map(DbDataReader reader)
    {
        T entity = new T();
        Type type = typeof(T);
        
        for(int i = 0; i < reader.FieldCount; i++)
        {
            string name = reader.GetName(i);
            PropertyInfo prop = type.GetProperty(name);
            
            if(prop != null && !reader.IsDBNull(i))
            {
                object value = reader.GetValue(i);
                prop.SetValue(entity, value);
            }
        }
        
        return entity;
    }
}

8.最佳实践

8.1 反射使用准则

  1. 避免滥用:只在真正需要动态行为的场景使用

  2. 性能敏感:高频调用路径避免使用反射

  3. 安全考虑:反射可以绕过访问限制,需谨慎

  4. 缓存优化:重复使用的反射对象要缓存

  5. 错误处理:反射调用要做好异常处理

8.2 替代方案

场景反射方案替代方案
动态创建对象Activator.CreateInstance工厂模式
方法调用MethodInfo.Invoke委托/接口
属性访问PropertyInfo.Get/Set动态表达式
插件系统反射加载DI容器

附录:常用反射工具方法

public static class ReflectionUtil
{
    // 获取友好类型名称
    public static string GetFriendlyTypeName(Type type)
    {
        if(!type.IsGenericType) return type.Name;
        
        string name = type.Name.Split('`')[0];
        var args = type.GetGenericArguments()
                     .Select(t => GetFriendlyTypeName(t));
        return $"{name}<{string.Join(",", args)}>";
    }
    
    // 深度克隆对象
    public static T DeepClone<T>(T obj)
    {
        if(obj == null) return default;
        
        Type type = obj.GetType();
        if(type.IsValueType || type == typeof(string))
            return obj;
            
        if(type.IsArray)
        {
            Array array = (Array)(object)obj;
            Array cloned = (Array)array.Clone();
            for(int i = 0; i < array.Length; i++)
                cloned.SetValue(DeepClone(array.GetValue(i)), i);
            return (T)(object)cloned;
        }
        
        T clonedObj = (T)Activator.CreateInstance(type);
        foreach(FieldInfo field in type.GetFields(
            BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
        {
            field.SetValue(clonedObj, DeepClone(field.GetValue(obj)));
        }
        
        return clonedObj;
    }
}

结语

"反射之道,始于探查,精于动态,成于性能。初窥门径易,登堂入室难。望诸君勤加修炼,早日渡劫飞升!"
——.NET修仙日记

微信公众号【.NET修仙日记】 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

.NET修仙日记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值