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

C# WPF中替代反射实现类属性动态赋值的高效方法

替代反射的高效动态赋值方案

针对你WPF应用中动态表头的属性赋值需求,这里提供几种无需反射、性能更优的实现方式:

方案一:用数组替代固定命名属性(最简洁高效)

直接用数组存储动态列值,完全避开反射和类属性的繁琐映射,性能最优:

public class StudentMark
{
    // 最多支持10列,和你原来的Col1-Col10对应
    public double?[] Columns { get; set; } = new double?[10];
}

赋值逻辑简化为:

StudentMark sm = new StudentMark();
int columnIndex = 0;
foreach (string str in HeaderColumns)
{
    if (columnIndex >= sm.Columns.Length) break; // 防止越界
    var cellValue = csv.GetField<string>(str);
    // 可添加格式验证,避免转换错误
    if (double.TryParse(cellValue, out double value))
    {
        sm.Columns[columnIndex] = value;
    }
    else
    {
        sm.Columns[columnIndex] = null;
    }
    columnIndex++;
}

这种方式直接通过索引操作数组,无任何反射开销,代码简洁,后续图表绘制时直接遍历数组即可。

方案二:预编译Set委托(兼顾类结构和性能)

如果必须保留StudentMark的Col1-Col10属性结构,可以提前用表达式树编译属性的Set方法,仅在程序初始化时做一次反射操作,后续赋值直接调用委托:

首先,提前初始化委托列表(全局或类静态变量,仅初始化一次):

private static readonly List<Action<StudentMark, double?>> _columnSetters;

static StudentMark()
{
    _columnSetters = new List<Action<StudentMark, double?>>();
    // 按Order属性排序获取目标属性
    var properties = typeof(StudentMark).GetProperties()
        .Where(p => Attribute.IsDefined(p, typeof(OrderAttribute)))
        .OrderBy(p => ((OrderAttribute)p.GetCustomAttributes(typeof(OrderAttribute), false).Single()).Order)
        .ToList();

    foreach (var prop in properties)
    {
        // 用表达式树生成属性Set委托
        var instanceParam = Expression.Parameter(typeof(StudentMark), "instance");
        var valueParam = Expression.Parameter(typeof(double?), "value");
        var propertyAccess = Expression.Property(instanceParam, prop);
        var assignExpr = Expression.Assign(propertyAccess, valueParam);
        var setter = Expression.Lambda<Action<StudentMark, double?>>(assignExpr, instanceParam, valueParam).Compile();
        _columnSetters.Add(setter);
    }
}

然后赋值逻辑简化为:

StudentMark sm = new StudentMark();
int columnIndex = 0;
foreach (string str in HeaderColumns)
{
    if (columnIndex >= _columnSetters.Count) break;
    var cellValue = csv.GetField<string>(str);
    double? value = double.TryParse(cellValue, out double val) ? val : null;
    _columnSetters[columnIndex](sm, value);
    columnIndex++;
}

这种方式仅在首次使用StudentMark时做一次反射和委托编译,后续赋值性能与直接调用属性setter几乎一致。

方案三:手动硬编码映射(性能极致,适合列数固定场景)

如果列数固定为最多10列,且表头顺序与Col1-Col10的Order属性严格对应,可直接手动赋值,完全无反射开销:

StudentMark sm = new StudentMark();
int columnIndex = 0;
foreach (string str in HeaderColumns)
{
    var cellValue = csv.GetField<string>(str);
    double? value = double.TryParse(cellValue, out double val) ? val : null;
    switch (columnIndex)
    {
        case 0: sm.Col1 = value; break;
        case 1: sm.Col2 = value; break;
        case 2: sm.Col3 = value; break;
        case 3: sm.Col4 = value; break;
        case 4: sm.Col5 = value; break;
        case 5: sm.Col6 = value; break;
        case 6: sm.Col7 = value; break;
        case 7: sm.Col8 = value; break;
        case 8: sm.Col9 = value; break;
        case 9: sm.Col10 = value; break;
        default: break;
    }
    columnIndex++;
}

这种方式代码虽有冗余,但性能达到极致,适合数据量极大、对性能要求苛刻的场景。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 18:31:08