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

C#循环内按属性名取类属性值 有无无需每次反射的高性能方案?

优化方案:缓存属性访问委托避免循环内重复反射

核心逻辑:仅在首次遇到指定属性名时做一次元数据查询、委托构建,后续所有调用直接复用缓存的取值委托,循环内无任何反射开销,性能接近硬编码取值。

方案1:通用动态缓存方案(支持任意新增字段/属性,无需修改业务代码)

首先定义线程安全的静态缓存,同属性名全局复用委托:

using System.Collections.Concurrent;
using System.Linq.Expressions;
using System.Reflection;

public class YourServiceClass
{
    // 缓存键:属性/字段名,缓存值:从Product实例取对应值的强类型委托
    private static readonly ConcurrentDictionary<string, Func<Product, string>> _productValueGetterCache
        = new ConcurrentDictionary<string, Func<Product, string>>();

    public void SetCopyProperty(List<Product> products, string propertyName)
    {
        // 缓存中不存在则自动构建委托,存在直接取
        var getValue = _productValueGetterCache.GetOrAdd(propertyName, name =>
        {
            // 适配字段、属性两种成员类型
            MemberInfo member = typeof(Product).GetField(name);
            member ??= typeof(Product).GetProperty(name);
            
            if (member == null)
            {
                throw new ArgumentException($"Product类型中不存在名为{name}的公共字段/属性", nameof(propertyName));
            }

            // 表达式树构建取值委托
            var instanceParam = Expression.Parameter(typeof(Product), "instance");
            var memberAccess = Expression.MakeMemberAccess(instanceParam, member);
            return Expression.Lambda<Func<Product, string>>(memberAccess, instanceParam).Compile();
        });

        // 循环内直接调用委托,无反射开销
        foreach (var product in products)
        {
            product.Copy = getValue(product);
        }
    }
}

如果是.NET 5+环境,可以替换表达式树部分为官方封装的CreateGetter方法,代码更简洁:

// 替换表达式树构建部分即可
if (member is FieldInfo field)
{
    return (Func<Product, string>)field.CreateGetter<Product>();
}
else if (member is PropertyInfo prop)
{
    return (Func<Product, string>)prop.CreateGetter<Product>();
}

方案2:固定属性枚举方案(性能最高,适用于属性不会频繁新增的场景)

如果取值的字段是固定的几个(当前场景下只有Title、Description两个可选),可以直接用开关表达式硬编码委托,连首次构建委托的开销都完全消除:

public void SetCopyProperty(List<Product> products, string propertyName)
{
    Func<Product, string> getValue = propertyName switch
    {
        nameof(Product.Title) => p => p.Title,
        nameof(Product.Description) => p => p.Description,
        _ => throw new ArgumentException($"不支持的属性名{propertyName}", nameof(propertyName))
    };

    foreach (var product in products)
    {
        product.Copy = getValue(product);
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.12 07:18:00