ListExtensions.cs 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.Collections.Generic;
  4. using System.Data;
  5. using System.Linq;
  6. using System.Text;
  7. using System.Threading.Tasks;
  8. using System.Windows.Forms;
  9. namespace PTMedicalInsurance.CustomExtensions
  10. {
  11. public class FieldMapping<T>
  12. {
  13. // 缓存字典(避免重复转换 DataTable)
  14. private static readonly ConcurrentDictionary<string, Dictionary<string, string>> _cache
  15. = new ConcurrentDictionary<string, Dictionary<string, string>>();
  16. public Func<T, string> SourceValueSelector { get; }
  17. public Dictionary<string, string> LookupMap { get; }
  18. public Action<T, string> ValueAssigner { get; }
  19. public FieldMapping(
  20. Func<T, string> sourceValueSelector,
  21. Dictionary<string, string> lookupMap,
  22. Action<T, string> valueAssigner)
  23. {
  24. SourceValueSelector = sourceValueSelector;
  25. LookupMap = lookupMap;
  26. ValueAssigner = valueAssigner;
  27. }
  28. // 用于创建“空映射”——不进行任何替换
  29. private static readonly Dictionary<string, string> _emptyMap = new Dictionary<string, string>();
  30. /// <summary>
  31. /// 安全创建字段映射:任何错误都静默处理,不抛异常
  32. /// </summary>
  33. public static FieldMapping<T> For(
  34. Func<T, string> sourceValueSelector,
  35. DataTable sourceTable,
  36. string codeColumn,
  37. string nameColumn,
  38. Action<T, string> valueAssigner)
  39. {
  40. // ✅ 任何环节出错都返回“空映射”,不抛异常
  41. try
  42. {
  43. // 1. 参数为空?→ 跳过
  44. if (sourceValueSelector == null || sourceTable == null ||
  45. string.IsNullOrEmpty(codeColumn) || string.IsNullOrEmpty(nameColumn) ||
  46. valueAssigner == null)
  47. {
  48. return new FieldMapping<T>(sourceValueSelector, _emptyMap, valueAssigner);
  49. }
  50. // 2. 列不存在?→ 跳过
  51. if (!sourceTable.Columns.Contains(codeColumn) || !sourceTable.Columns.Contains(nameColumn))
  52. {
  53. return new FieldMapping<T>(sourceValueSelector, _emptyMap, valueAssigner);
  54. }
  55. // 3. 表为空?→ 跳过
  56. if (sourceTable.Rows.Count == 0)
  57. {
  58. return new FieldMapping<T>(sourceValueSelector, _emptyMap, valueAssigner);
  59. }
  60. // 4. 提取字典(使用缓存)
  61. string key = $"{sourceTable.TableName ?? "Table"}_{codeColumn}_{nameColumn}";
  62. var map = _cache.GetOrAdd(key, _ =>
  63. {
  64. try
  65. {
  66. return sourceTable.AsEnumerable()
  67. .Where(row => !row.IsNull(codeColumn))
  68. .ToDictionary(
  69. row => row.Field<string>(codeColumn),
  70. row => row.Field<string>(nameColumn) ?? "",
  71. StringComparer.OrdinalIgnoreCase);
  72. }
  73. catch
  74. {
  75. // 字典构建失败 → 返回空字典
  76. return _emptyMap;
  77. }
  78. });
  79. return new FieldMapping<T>(sourceValueSelector, map, valueAssigner);
  80. }
  81. catch
  82. {
  83. // ✅ 所有异常都被捕获,返回空映射
  84. return new FieldMapping<T>(sourceValueSelector, _emptyMap, valueAssigner);
  85. }
  86. }
  87. }
  88. public static class ListExtensions
  89. {
  90. /// <summary>
  91. /// 将 List 中某字段的值通过映射表转换为新值,并返回新 List(不修改原对象)
  92. /// </summary>
  93. /// <typeparam name="T">列表元素类型</typeparam>
  94. /// <param name="list">源列表</param>
  95. /// <param name="sourceFieldSelector">要转换的字段(如 x => x.Status)</param>
  96. /// <param name="mapTable">映射表(含 Code 和 Description 列)</param>
  97. /// <param name="keyColumn">映射表中键列名(如 "Code")</param>
  98. /// <param name="valueColumn">映射表中值列名(如 "Description")</param>
  99. /// <param name="converter">转换后设置值的委托(如 x => x.StatusDesc = value)</param>
  100. /// <returns>返回新 List,字段已转换</returns>
  101. public static List<T> MapField<T>(
  102. this List<T> list,
  103. Func<T, object> sourceFieldSelector,
  104. DataTable mapTable,
  105. string keyColumn,
  106. string valueColumn,
  107. Action<T, string> converter)
  108. {
  109. if ((mapTable == null) || mapTable.Rows.Count == 0)
  110. {
  111. }
  112. // 构建映射字典
  113. var dict = mapTable.AsEnumerable()
  114. .ToDictionary(
  115. r => r.Field<object>(keyColumn),
  116. r => r.Field<string>(valueColumn)
  117. );
  118. foreach (var item in list)
  119. {
  120. var key = sourceFieldSelector(item);
  121. var value = dict.TryGetValue(key, out string mapped) ? mapped : key.ToString();
  122. converter(item, value);
  123. }
  124. return list; // 返回原列表(已修改),也可 new List 返回副本
  125. }
  126. public static List<T> MapFields<T>(this List<T> list, params FieldMapping<T>[] mappings)
  127. {
  128. // 空列表或 null → 直接返回
  129. if (list == null || list.Count == 0 || mappings == null || mappings.Length == 0)
  130. return list;
  131. foreach (var item in list)
  132. {
  133. foreach (var mapping in mappings)
  134. {
  135. try
  136. {
  137. string code = mapping.SourceValueSelector(item);
  138. if (string.IsNullOrEmpty(code))
  139. continue;
  140. if (mapping.LookupMap.TryGetValue(code, out string desc))
  141. {
  142. mapping.ValueAssigner(item, desc);
  143. }
  144. }
  145. catch
  146. {
  147. // 单个对象处理失败,不影响其他对象
  148. continue;
  149. }
  150. }
  151. }
  152. return list;
  153. }
  154. }
  155. }