C#Linq .ToDictionary()密钥已经存在

最终编辑:我能够找到ini文件中的重复字段。 谢谢大家的帮助!

我正在使用正则表达式来解析ini文件,使用LINQ将其存储在Dictionary中:

样本数据:
[WindowSettings]
窗口X Pos =’0′
窗口Y Pos =’0′
Window Maximized =’false’
窗口名称=’Jabberwocky’

[记录]
目录=’C:\ Rosetta Stone \ Logs’

编辑:这是实际导致问题的文件: http : //pastebin.com/mQSrkrcP

EDIT2:我把它缩小到由文件的最后一部分引起:[list_first_nonprintable]

由于某种原因,我正在解析的文件之一是抛出此exception:

System.ArgumentException:已添加具有相同键的项。

有没有办法让我找出导致问题的键(所以我可以修复文件),或者只是跳过导致这个问题的键并继续解析?

这是代码:

try { // Read content of ini file. string data = System.IO.File.ReadAllText(project); // Create regular expression to parse ini file. string pattern = @"^((?:\[)(?
[^\]]*)(?:\])(?:[\r\n]{0,}|\Z))((?!\[)(?[^=]*?)(?:=)(?[^\r\n]*)(?:[\r\n]{0,4}))*"; //pattern = @" //^ # Beginning of the line //((?:\[) # Section Start // (?
[^\]]*) # Actual Section text into Section Group // (?:\]) # Section End then EOL/EOB // (?:[\r\n]{0,}|\Z)) # Match but don't capture the CRLF or EOB // ( # Begin capture groups (Key Value Pairs) // (?!\[) # Stop capture groups if a [ is found; new section // (?[^=]*?) # Any text before the =, matched few as possible // (?:=) # Get the = now // (?[^\r\n]*) # Get everything that is not an Line Changes // (?:[\r\n]{0,4}) # MBDC \r\n // )* # End Capture groups"; // Parse each file into a Dictionary. Dictionary<string, Dictionary> iniFile = (from Match m in Regex.Matches(data, pattern, RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline) select new { Section = m.Groups["Section"].Value, kvps = (from cpKey in m.Groups["Key"].Captures.Cast().Select((a, i) => new { a.Value, i }) join cpValue in m.Groups["Value"].Captures.Cast().Select((b, i) => new { b.Value, i }) on cpKey.i equals cpValue.i select new KeyValuePair(cpKey.Value, cpValue.Value)).ToDictionary(kvp => kvp.Key, kvp => kvp.Value) }).ToDictionary(itm => itm.Section, itm => itm.kvps); return iniFile; } catch (ArgumentException ex) { System.Diagnostics.Debug.Write(ex.ToString()); return new Dictionary<string, Dictionary>(); }

提前致谢。

这只是意味着当你转换为字典时 –

 .ToDictionary(itm => itm.Section, itm => itm.kvps); 

– 有多个键(itm.Section)。 您可以使用ToLookup ,它有点像字典但允许多个键。

编辑

有几种方法可以调用ToLookup 。 最简单的是指定键选择器:

 var lookup = // ... .ToLookup(itm => itm.Section); 

这应该提供一个查找,其中键的类型为Group 。 获取查找值应返回IEnumerable,其中T是匿名类型:

 Group g = null; // TODO get group var lookupvalues = lookup[g]; 

如果.NET编译器不喜欢这个(有时它似乎很难弄清楚各种类型应该是什么),你也可以指定一个元素选择器,例如:

 ILookup> lookup = // ... .ToLookup( itm => itm.Section.Value, // key selector itm => itm.kvps // element selector ); 

您可以编写自己的ToDictionary方法,该方法不会轻易破坏重复键。

 public static Dictionary ToDictionary( this IEnumerable source, Func keySelector, Funct valueSelector) { //TODO validate inputs for null arguments. Dictionary output = new Dictionary(); foreach(TSource item in source) { //overwrites previous values output[keySelector(item)] = valueSelector(item); //ignores future duplicates, comment above and //uncomment below to change behavior //K key = keySelector(item); //if(!output.ContainsKey(key)) //{ //output.Add(key, valueSelector(item)); //} } return output; } 

我假设你可以弄清楚如何实现额外的重载(没有值选择器)。

您可以使用Tuple传递多个键。 检查下面的示例代码:

 .ToDictionary(k => new Tuple(k.key1,k.key2), v => v.value)