C#中替代Reflection实现动态字段映射的方案求助
高效映射Amounts列表到指定属性的替代方案
问题场景
我在C#类中定义了20个带JsonProperty特性的字符串属性(从LTRAMT1到LTRAMT20),需要根据请求体中amounts列表的position值,将对应value映射到对应属性。目前已实现LtrAmounts方法用于匹配position获取value,使用反射实现映射功能正常但响应时间过长;尝试用Dictionary实现时,响应会生成嵌套的LTRAMT父对象,不符合输出要求,寻求可行替代方案。
类属性示例:
[JsonProperty("LTR-AMT-1")] public string? LTRAMT1 { get; set; } // LTRAMT2至LTRAMT20定义类似
LtrAmounts方法代码:
public static string LtrAmounts(List<Amounts> amounts, int i) { var filter = amounts.FirstOrDefault(x => x.position == i); return filter != null ? filter.value.ToString() : ""; }
请求体示例:
"amounts": [ {"value": 0,"position": 1}, {"value": 1624.96,"position": 2}, {"value": 9901010,"position": 4}, {"value": 35776,"position": 20} ]
可行替代方案
方案1:预编译表达式树构建赋值委托字典
通过表达式树预编译每个属性的赋值委托,初始化时构建一次position到委托的字典,后续赋值直接调用委托,性能接近硬编码赋值,同时兼顾代码维护性。
代码示例:
// 假设Amounts类结构 public class Amounts { public decimal value { get; set; } public int position { get; set; } } public class TargetClass { [JsonProperty("LTR-AMT-1")] public string? LTRAMT1 { get; set; } [JsonProperty("LTR-AMT-2")] public string? LTRAMT2 { get; set; } // ... 其余18个属性定义 // 静态字典存储position到属性赋值委托 private static readonly Dictionary<int, Action<TargetClass, string>> _positionSetters; static TargetClass() { _positionSetters = new Dictionary<int, Action<TargetClass, string>>(); var type = typeof(TargetClass); for (int i = 1; i <= 20; i++) { var property = type.GetProperty($"LTRAMT{i}"); if (property == null) continue; // 构建表达式树生成赋值委托 var instanceParam = Expression.Parameter(typeof(TargetClass), "instance"); var valueParam = Expression.Parameter(typeof(string), "value"); var assignExpr = Expression.Assign(Expression.Property(instanceParam, property), valueParam); var setter = Expression.Lambda<Action<TargetClass, string>>(assignExpr, instanceParam, valueParam).Compile(); _positionSetters.Add(i, setter); } } public void MapAmounts(List<Amounts> amounts) { // 先将amounts转为字典,将O(n)查找优化为O(1) var amountDict = amounts.ToDictionary(a => a.position, a => a.value.ToString()); foreach (var kvp in _positionSetters) { kvp.Value(this, amountDict.TryGetValue(kvp.Key, out var val) ? val : ""); } } }
方案2:硬编码赋值逻辑(性能最优)
直接编写20个属性的赋值代码,完全避免反射或字典的额外开销,性能达到峰值,适合属性数量固定的场景。
代码示例:
public class TargetClass { [JsonProperty("LTR-AMT-1")] public string? LTRAMT1 { get; set; } [JsonProperty("LTR-AMT-2")] public string? LTRAMT2 { get; set; } // ... 其余18个属性定义 public void MapAmounts(List<Amounts> amounts) { var amountDict = amounts.ToDictionary(a => a.position, a => a.value.ToString()); LTRAMT1 = amountDict.TryGetValue(1, out var val1) ? val1 : ""; LTRAMT2 = amountDict.TryGetValue(2, out var val2) ? val2 : ""; LTRAMT3 = amountDict.TryGetValue(3, out var val3) ? val3 : ""; // ... 依次编写LTRAMT4至LTRAMT20的赋值逻辑 LTRAMT20 = amountDict.TryGetValue(20, out var val20) ? val20 : ""; } }
方案3:优化查找逻辑+直接赋值
先将amounts列表转为Dictionary<int, decimal>,把原有的O(n)查找优化为O(1),再结合直接赋值,既解决反射性能问题,又避免字典导致的嵌套对象输出问题。
代码示例:
public void MapAmounts(List<Amounts> amounts) { var amountDict = amounts.ToDictionary(a => a.position, a => a.value); LTRAMT1 = amountDict.ContainsKey(1) ? amountDict[1].ToString() : ""; LTRAMT2 = amountDict.ContainsKey(2) ? amountDict[2].ToString() : ""; // ... 其余属性同理赋值 LTRAMT20 = amountDict.ContainsKey(20) ? amountDict[20].ToString() : ""; }
内容的提问来源于stack exchange,提问作者Prajwal MR
相关产品推荐
相关产品推荐

