C#中如何将ConcurrentDictionary数据填充到DataTable指定单元格
看起来你想把嵌套的ConcurrentDictionary结构转换成一个行列分明的DataTable——其中行对应唯一的Two键,列对应所有的One键加上一个TwoDetails列来标注当前行的Two标识。我来帮你完善代码,同时修正一些线程安全的问题:
完整实现代码
// 假设你的源字典已经初始化并填充了数据 ConcurrentDictionary<string, ConcurrentDictionary<string, string>> OneTwoThree = new ConcurrentDictionary<string, ConcurrentDictionary<string, string>>(); DataTable dt = new DataTable(); // 先添加固定列 dt.Columns.Add("TwoDetails", typeof(string)); // 步骤1:收集所有需要的列(外层字典的Key)和行标识(所有内层字典的Key,去重) // 注意:Parallel操作下非线程安全集合会出问题,所以用ConcurrentBag先收集再去重 ConcurrentBag<string> allOneKeys = new ConcurrentBag<string>(); ConcurrentBag<string> allTwoKeys = new ConcurrentBag<string>(); Parallel.ForEach(OneTwoThree, oneEntry => { allOneKeys.Add(oneEntry.Key); foreach (var twoEntry in oneEntry.Value) { allTwoKeys.Add(twoEntry.Key); } }); // 去重并添加One列到DataTable foreach (var oneKey in allOneKeys.Distinct()) { dt.Columns.Add(oneKey, typeof(string)); } // 去重得到唯一的Two键集合 var distinctTwoKeys = allTwoKeys.Distinct(); // 步骤2:填充每一行数据 foreach (var twoKey in distinctTwoKeys) { DataRow row = dt.NewRow(); row["TwoDetails"] = twoKey; foreach (var oneKey in allOneKeys.Distinct()) { // 尝试从外层字典中取出对应的内层字典,再尝试取出TwoKey对应的值 if (OneTwoThree.TryGetValue(oneKey, out var twoDict) && twoDict.TryGetValue(twoKey, out var value)) { row[oneKey] = value; } else { // 如果没有对应值,填充DBNull或者空字符串,根据你的需求调整 row[oneKey] = DBNull.Value; } } dt.Rows.Add(row); }
关键修正和说明
- 线程安全问题:你之前用
HashSet在Parallel.ForEach里Add是不安全的,因为HashSet不是线程安全集合,并发操作会导致数据丢失或异常。这里换成ConcurrentBag来收集所有键,之后再用Distinct()去重,既保证并发安全又能得到唯一值。 - 列的添加时机:不要在并行循环里直接操作
DataTable.Columns(它也不是线程安全的),先收集所有需要的列名,再统一添加,避免多线程冲突。 - 数据填充逻辑:遍历每个唯一的
Two键创建行,然后逐个检查每个One键下是否存在该Two的对应值,存在则填充,不存在则用DBNull.Value(适合数据库场景)或空字符串填充,你可以根据需求调整。
如果你的目标DataTable结构和我假设的不一样,可以补充说明具体的预期效果,我再帮你调整~
内容的提问来源于stack exchange,提问作者Naira
相关产品推荐
相关产品推荐

