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
相关产品推荐
相关产品推荐

