当前位置: 首页 > 编程语言 > C#

c#SortedList.ContainsKey表示成功添加key返回falseshare

时间:2023-04-11 01:40:13 C#

c#SortedList.ContainsKey表示成功添加key返回false检查下方更新3我发现我在.Net4.0,4.0上遇到的问题客户端是与4.5的c#字符串比较器的一个已知严重问题有关,这会导致字符串列表以不一致的顺序排序(导致输出取决于输入的顺序和使用的排序算法)。该问题已于2012年12月报告给Microsoft,并以“Won'tfix”结束。有一种解决方法,但速度要慢得多,而且对于大型集合来说几乎不实用。在实现不可变的PatriciaTrie时,我想将其性能与System.Collections.Generic.SortedList进行比较。我使用以下文件https://github.com/rkapsi/patricia-trie/blob/master/src/test/resources/org/ardverk/collection/hamlet.txt创建用于测试的输入词汇表。在c#SortedList中插入每个单词时,使用Comparer.Default或StringComparer.InvariantCulture作为键比较器,无法检索使用正常搜索方法成功插入的多个条目(例如ContainsKey返回false),但通过迭代列表观察到的键存在于列表中。更奇怪的是,当比较从排序列表中检索到的键与使用ContainsKey找不到的搜索键时,比较器返回值“0”。下面的完整示例演示了我系统上的这个问题。使用系统;使用System.IO;使用System.Linq;使用System.Collections.Generic;classProgram{staticvoidMain(string[]args){//问题可能与比较有关。变种失败=真;变种比较器=失败?StringComparer.InvariantCulture:StringComparer.Ordinal;//读取hamlet(包含重复的单词)varwords=File.ReadAllLines("hamlet.txt").SelectMany(l=>l.Split(new[]{'','t'},StringSplitOptions.RemoveEmptyEntries)).选择(w=>w.Trim()).Where(w=>!string.IsNullOrEmpty(w)).Distinct(比较器).ToArray();//将hamlet的单词插入排序列表中。varlist=newSortedList(比较器);varndx=0;foreach(varwordinwords)list[word]=ndx++;//搜索每个添加的单词。foreach(varkeyToSearchinwords){if(!list.ContainsKey(keyToSearch)){//已插入,但无法检索。Console.WriteLine("错误-未找到密钥:"{0}"",keyToSearch);//但是当我们遍历列表时,我们看到条目存在varprefix=keyToSearch.Substring(0,Math.Min(keyToSearch.Length,3));foreach(varwordCloseToSearchKeyinlist.Keys.Where(s=>s.StartsWith(prefix))){//并使用SortedList提供的比较返回0,表示相等varcomparisonResult=list.Comparer.Compare(wordCloseToSearchKey,keyToSearch);Console.WriteLine("{0}-比较结果={1}",wordCloseToSearchKey,comparisonResult);}}}//检查List.Keys的排序顺序是否正确varkeys=list.Keys.ToArray();BinarySearchAll("list.Keys",keys,list.Comparer);CheckCorrectSortOrder("list.Keys",keys,list.Comparer);//检查Array.Sort(List.Keys)的排序顺序是否正确vararraySortedKeys=CopySortSearchAndCheck("Array.Sort(List.Keys)",keys,list.Comparer);//检查Array.Sort(inputwords)的排序顺序是否正确varsortedInput=CopySortSearchAndCheck("Array.Sort(inputwords)",words,list.Comparer);安慰。读线();}staticstring[]CopySortSearchAndCheck(stringarrayDesc,string[]input,IComparercomparer){//复制输入varsortedInput=newstring[input.Length];Array.Copy(输入,sortedInput,sortedInput.Length);//排序Array.Sort(sortedInput,comparer);//检查我们是否真的可以使用bin找到数组中的键。搜索BinarySearchAll(arrayDesc,sortedInput,比较器);//检查排序顺序是否正确CheckCorrectSortOrder(arrayDesc,sortedInput,comparer);返回排序输入;}staticvoidBinarySearchAll(stringarrayDesc,string[]sortedInput,IComparercomparer){//检查是否可以使用bin找到输入中的每个键。searchforeach(varwordinsortedInput){varix=Array.BinarySearch(sortedInput,word,comparer);if(ix<0)//看来它不能!Console.WriteLine("错误-{0}-未找到密钥:"{1}"",arrayDesc,word);}}staticvoidCheckCorrectSortOrder(stringarrayDesc,string[]sortedKeys,IComparer比较器){for(intn=0;n'a)结论似乎是依赖于c#字符串编译器确定的排序顺序是不安全的,还是我错过了什么?更新3这个问题似乎已于2012年12月报告给MS,并以“无法修复”状态结束,这令人相当失望;请参阅下面评论中发布的链接(由于我有限的声誉点,我似乎不能在这里发布。这也列出了一个解决方法,我已经实施并用于验证这确实解决了标准比较器观察到的问题。公共类WorkAroundStringComparer:StringComparer{privatestaticreadonlyFunc_getHashCodeOfString;私人只读比较信息_比较信息;私人只读比较选项_compareOptions;staticWorkAroundStringComparer(){//需要此内部方法来计算哈希码//作为IEqualityComparer实现。_getHashCodeOfString=BuildGetHashCodeOfStringDelegate();}staticFuncBuildGetHashCodeOfStringDelegate(){varcompareInfoType=typeof(CompareInfo);varargTypes=new[]{typeof(string),typeof(CompareOptions)};var标志=BindingFlags.NonPublic|BindingFlags.Instance;varmethods=compareInfoType.GetMethods(flags).ToArray();;varmethod=compareInfoType.GetMethod("GetHashCodeOfString",flags,null,argTypes,null);varinstance=Expression.Parameter(compareInfoType,"instance");varstringArg=Expression.Parameter(typeof(string),"string");varoptionsArg=Expression.Parameter(typeof(CompareOptions),"选项s");varmethodCall=Expression.Call(instance,method,stringArg,optionsArg);varexpr=Expression.Lambda(methodCall,instance,stringArg,optionsArg);returnexpr.Compile();}publicWorkAroundStringComparer():this(CultureInfo.InvariantCulture){}publicWorkAroundStringComparer(CultureInfocultureInfo,CompareOptionscompareOptions=CompareOptions.None){if(cultureInfo==null)thrownewArgumentNullException("cultureInfo");this._compareInfo=cultureInfo.CompareInfo;这。_compareOptions=compareOptions;}publicoverrideintCompare(stringx,stringy){if(ReferenceEquals(x,y))返回0;if(ReferenceEquals(x,null))返回-1;if(ReferenceEquals(y,null))返回1;varsortKeyFor_x=_compareInfo.GetSortKey(x,_compareOptions);varsortKeyFor_y=_compareInfo.GetSortKey(y,_compareOptions);returnSortKey.Compare(sortKeyFor_x,sortKeyFor_y);}publicoverrideboolEquals(stringx,stringy){返回比较(x,y)==0;}publicoverrideintGetHashCode(stringobj){return_getHashCodeOfString(_compareInfo,obj,_compareOptions);这种解决方法的问题是它对于大型集合几乎不实用,因为它比例如慢StringComparer.InvariantCulture使用两个比较器对给定单词列表进行1000次排序所花费的时间数量级:StringComparer.InvariantCulture:00:00:15.3120013WorkAroundStringComparer:00:01:35.8322409所以我仍然希望微软重新考虑或有人知道可行的方法选择。否则,剩下的唯一选择就是使用StringComparer.Ordinal。它可能与.NetFramework4/4.5有关吗?我已经为您的.Net3.5改编了这个示例:varwords=ReadFile("hamlet.txt");//...privatestaticstring[]ReadFile(stringpath){列表行=newList();使用(StreamReadersr=newStreamReader(path)){stringtext=sr.ReadToEnd();lines.Add(文本);}returnlines.SelectMany(l=>l.Split(new[]{'','t'},StringSplitOptions.RemoveEmptyEntries).Select(w=>w.Trim())).Where(w=>!(w.ToCharArray().All(c=>c==''))).ToArray();两个比较器都可以在XP和.Net3.5上正常工作。以上是C#学习教程:c#SortedList.ContainsKey表示key添加成功返回false。代表立场,如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处: