LeetCode句子相似性题:字典键莫名消失问题排查
问题排查:Dictionary无显式修改却为空导致KeyNotFoundException
问题现象
编写LeetCode「sentence-similarity」题解时,出现异常:构建完成的Dictionary首次打印可正常显示键值对,但后续循环中无法找到已存在的键(如great),抛出System.Collections.Generic.KeyNotFoundException,且此时字典的键集合为空。
相关代码
public class Solution { public bool AreSentencesSimilar(string[] sentence1, string[] sentence2, IList<IList<string>> similarPairs) { // TODO: Validation int n = sentence1.Length; if (sentence2.Length != n) return false; IDictionary<string, ICollection<string>> synonyms = BuildSynonymLookup(similarPairs); // ------------------ TEST! --------------------- foreach (var kvp in synonyms) Console.WriteLine("{0} -> [{1}]", kvp.Key, string.Join(", ", kvp.Value)); /* The above prints great -> [fine, great] fine -> [great, fine] drama -> [acting, drama] acting -> [drama, acting] skills -> [talent, skills] talent -> [skills, talent] */ // ------------------------------------------------- for (int i = 0; i < n; ++i) { string word1 = sentence1[i], word2 = sentence2[i]; // --------------------- TEST! --------------------------- if (!synonyms.ContainsKey(word1)) { Console.WriteLine("synonyms does not contain '{0}'. It contains [{1}]", word1, string.Join(",", synonyms.Keys)); } // ---- The above prints 'synonyms does not contain great. It contains []' if (!synonyms[word1].Contains(word2)) // Unhandled exception. System.Collections.Generic.KeyNotFoundException: The given key 'great' was not present in the dictionary. return false; } return true; } private static IDictionary<string, ICollection<string>> BuildSynonymLookup(in IList<IList<string>> similarPairs) { var synonyms = new Dictionary<string, ICollection<string>>(similarPairs.Count); foreach (var pair in similarPairs) { string w0 = pair[0], w1 = pair[1]; AddSynonym(synonyms, w0, w1); AddSynonym(synonyms, w0, w0); AddSynonym(synonyms, w1, w0); AddSynonym(synonyms, w1, w1); } return synonyms; } private static void AddSynonym(in IDictionary<string, ICollection<string>> synonyms, in string word0, in string word1) { if (!synonyms.TryGetValue(word0, out ICollection<string> S)) synonyms[word0] = S = new HashSet<string>(4); S.Add(word1); } }
问题原因
问题出在**in关键字的误用**:
in关键字用于传递只读引用参数,设计目的是避免值类型的复制开销,同时保证参数不会被重新赋值。- 但对于
Dictionary这类可变引用类型,虽然in允许修改对象内部状态,但编译器在处理接口类型的in参数时,可能会触发异常的优化行为,导致后续访问时字典的引用失效或内部状态被异常重置。 - 你在
BuildSynonymLookup和AddSynonym方法的参数上都添加了in修饰符,这完全是多余的——你需要修改字典的内容,in的只读约束不仅没用,反而引发了异常行为。
解决方案
移除所有不必要的in关键字,修改后的方法签名如下:
private static IDictionary<string, ICollection<string>> BuildSynonymLookup(IList<IList<string>> similarPairs) // 移除参数前的in private static void AddSynonym(IDictionary<string, ICollection<string>> synonyms, string word0, string word1) // 移除所有参数前的in
移除后,字典的引用和内部状态将保持稳定,后续循环中可以正常访问已存在的键。
内容的提问来源于stack exchange,提问作者user2967799
相关产品推荐
相关产品推荐

