You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

长期反复通过反射读写属性值的最优实现方案咨询

重复反射操作属性的高效替代方案

普通反射的低效核心在于每次调用都会重复扫描元数据、执行类型检查,针对长期重复操作的场景,最优思路是提前缓存关键反射信息或生成可直接执行的代码委托,避免重复开销。以下是几种落地方案:

1. 缓存PropertyInfo实例

这是最易实现的优化方式,直接复用获取到的PropertyInfo,跳过重复的元数据查找:

// 全局缓存,按「类型+属性名」唯一标识存储
private static readonly Dictionary<(Type Type, string PropertyName), PropertyInfo> _propertyCache = new();

// 获取属性值
public static object GetPropertyValue(object obj, string propertyName)
{
    var key = (obj.GetType(), propertyName);
    if (!_propertyCache.TryGetValue(key, out var propInfo))
    {
        propInfo = key.Type.GetProperty(propertyName);
        _propertyCache[key] = propInfo;
    }
    return propInfo.GetValue(obj);
}

// 设置属性值
public static void SetPropertyValue(object obj, string propertyName, object value)
{
    var key = (obj.GetType(), propertyName);
    if (!_propertyCache.TryGetValue(key, out var propInfo))
    {
        propInfo = key.Type.GetProperty(propertyName);
        _propertyCache[key] = propInfo;
    }
    propInfo.SetValue(obj, value);
}

性能提升明显,适合属性操作频率中等的场景,代码维护成本极低。

2. 表达式树生成强类型委托

通过表达式树在运行时编译出直接操作属性的委托,性能接近手写代码调用,适合频繁操作属性的场景:

// 缓存编译后的获取委托
private static readonly Dictionary<(Type Type, string PropertyName), Func<object, object>> _getterCache = new();
// 缓存编译后的设置委托
private static readonly Dictionary<(Type Type, string PropertyName), Action<object, object>> _setterCache = new();

// 获取属性值
public static object GetPropertyValueFast(object obj, string propertyName)
{
    var key = (obj.GetType(), propertyName);
    if (!_getterCache.TryGetValue(key, out var getter))
    {
        var param = Expression.Parameter(typeof(object), "obj");
        var castParam = Expression.Convert(param, key.Type);
        var propertyAccess = Expression.Property(castParam, propertyName);
        var castResult = Expression.Convert(propertyAccess, typeof(object));
        getter = Expression.Lambda<Func<object, object>>(castResult, param).Compile();
        _getterCache[key] = getter;
    }
    return getter(obj);
}

// 设置属性值
public static void SetPropertyValueFast(object obj, string propertyName, object value)
{
    var key = (obj.GetType(), propertyName);
    if (!_setterCache.TryGetValue(key, out var setter))
    {
        var objParam = Expression.Parameter(typeof(object), "obj");
        var valueParam = Expression.Parameter(typeof(object), "value");
        var castObj = Expression.Convert(objParam, key.Type);
        var castValue = Expression.Convert(valueParam, key.Type.GetProperty(propertyName).PropertyType);
        var propertySet = Expression.Assign(Expression.Property(castObj, propertyName), castValue);
        setter = Expression.Lambda<Action<object, object>>(propertySet, objParam, valueParam).Compile();
        _setterCache[key] = setter;
    }
    setter(obj, value);
}

这种方案性能优于缓存PropertyInfo,且无需了解底层IL指令,平衡了性能与实现复杂度。

3. 动态生成IL指令

这是性能极致的方案,直接生成IL代码操作属性,执行效率几乎和手写属性调用一致,但实现复杂度高,适合对性能有极端要求的场景:

private static readonly Dictionary<(Type Type, string PropertyName), Func<object, object>> _ilGetterCache = new();

public static object GetPropertyValueIl(object obj, string propertyName)
{
    var key = (obj.GetType(), propertyName);
    if (!_ilGetterCache.TryGetValue(key, out var getter))
    {
        var propInfo = key.Type.GetProperty(propertyName);
        var getMethod = propInfo.GetGetMethod();
        var dynamicMethod = new DynamicMethod(
            $"Get_{key.Type.Name}_{propertyName}", 
            typeof(object), 
            new[] { typeof(object) }, 
            key.Type.Module);
        
        var il = dynamicMethod.GetILGenerator();
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Castclass, key.Type);
        il.Emit(OpCodes.Callvirt, getMethod);
        if (propInfo.PropertyType.IsValueType)
        {
            il.Emit(OpCodes.Box, propInfo.PropertyType);
        }
        il.Emit(OpCodes.Ret);
        
        getter = (Func<object, object>)dynamicMethod.CreateDelegate(typeof(Func<object, object>));
        _ilGetterCache[key] = getter;
    }
    return getter(obj);
}

需要对IL指令有基础了解,维护成本较高,但能达到原生调用的性能水准。

4. 借助第三方库简化实现

如果不想自己实现复杂的表达式树或IL逻辑,可以使用成熟的第三方库(如FastMember),它内部封装了上述高效方案,API简洁:

// 初始化类型访问器
var accessor = TypeAccessor.Create(obj.GetType());
// 获取属性值
var value = accessor[obj, propertyName];
// 设置属性值
accessor[obj, propertyName] = newValue;

库会自动缓存编译后的委托,性能接近表达式树方案,同时大幅降低开发成本。

长期视角的选择建议

  • 性能要求一般、追求易维护:优先选择缓存PropertyInfo
  • 频繁操作属性、平衡性能与复杂度:选择表达式树生成委托
  • 极致性能需求、能接受高维护成本:选择动态生成IL
  • 追求开发效率、不想重复造轮子:选择第三方库

内容的提问来源于stack exchange,提问作者VIktoriyaV

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 16:05:06