StringDictionary与Dictionary<string, string>的区别

83

有人知道System.Collections.Specialized.StringDictionary对象和System.Collections.Generic.Dictionary之间实际的区别吗?

我以前都用过它们,但从未考虑过哪一个性能更佳、在Linq中工作更好或提供其他任何优点。

有任何想法或建议可以告诉我为什么应该使用其中之一吗?

7个回答

97

Dictionary<string, string>是一种更现代的方法。它实现了IEnumerable<T>接口,更适合于LINQ风格的操作。

StringDictionary是旧的方式。它存在于泛型时代之前。我只会在与旧代码进行接口时使用它。


你应该进行基准测试,以查看哪种方法在你的特殊情况下表现更好。我不认为会有明显的性能差异。我建议在所有新代码中使用 Dictionary<string,string>(除非你需要针对1.1版本)。 - Mehrdad Afshari
2
@thecoop 目前我这边没有硬数据可以提供,但是之前我测试过 StringDictionary 的速度,结果表现得比较差(虽然这些大多数情况下并不重要)。说实话,我之前一直以为 StringDictionary 是一种专门用于加速以 string 作为键的集合类型,但是在我的测试中它表现得比较差,于是我上网搜索了一下,才发现它是非泛型的。 - nawfal
1
@nawfal 我认为它比较慢是因为StringDictionary默认情况下是不区分大小写的。如果你使用不区分大小写的键比较器创建一个Dictionary,我相信性能会相同。 - phuclv

44

另外一点。

这将返回 null:

StringDictionary dic = new StringDictionary();
return dic["Hey"];

这会抛出一个异常:

Dictionary<string, string> dic = new Dictionary<string, string>();
return dic["Hey"];

Dictionary<>的“抛出异常”特性意味着我永远不能使用[]。使用StringDictionary已经清理了我的大部分代码。 - James Curran
1
@James 我有点晚了,但你应该使用 TryGetValue。 - Şafak Gür
@ŞafakGür -- 我确实使用TryGetValue() -- 因为我永远不能使用 [ ],因为它会抛出异常。(StringDictionary只能解决一种类型的字典问题) - James Curran
@James,我认为对于不存在的键抛出异常是更好的API选择,因为null被允许作为字典值。这样你就可以区分一个不存在的键和其值为null的键。 - Şafak Gür
1
@ŞafakGür 这是真的 - 如果您需要一个字典,它a)应始终具有所有值,b)可以包含null,并且c)这些null意味着与“没有值”不同的东西。 但是,在字典中,“没有值”通常由键不存在表示。 然而,Dictionary<>抛出异常的真正原因是该值可能是值类型(因此,无法用null表示)。 - James Curran
1
通用字典在键不存在时抛出异常的原因是因为如果它返回default(TValue),那么就不可能区分字典是否具有Valuedefault(TValue)的项或不包含与Key匹配的KeyValuePair。这就是为什么大多数情况下使用TryGetValue是有意义的原因。请注意,可以通过使用((IDictionary)dic)["Hey"];来获得抛出异常的行为,但只应针对参考类型(如果有的话)进行此操作。 - NightOwl888

41

正如Reed Copsey所指出的那样,StringDictionary会将你的键值转为小写。这对我来说是完全意外的,并且是一个致命问题。

private void testStringDictionary()
{
    try
    {
        StringDictionary sd = new StringDictionary();
        sd.Add("Bob", "My name is Bob");
        sd.Add("joe", "My name is joe");
        sd.Add("bob", "My name is bob"); // << throws an exception because
                                         //    "bob" is already a key!
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

我在添加此回复以引起更多关注,因为我认为这个巨大的差异比现代与老派的区别更为重要。


5
如果出于某种原因,想要在 Dictionary<string, string> 中实现相同的行为,可以使用以下方法:Dictionary ht = new Dictionary(StringComparer.OrdinalIgnoreCase); ht.Add("Bob", "ff"); ht.Add("bob", "ff"); // 抛出异常 - osexpert

41
我认为 StringDictionary 已经相当过时了。它存在于 v1.1 框架中(在泛型之前),因此在当时它是一种更高级的版本(与非泛型 Dictionary 相比),但在这一点上,我不认为它有任何特定的优势,胜过 Dictionary。
然而,StringDictionary 有缺点。StringDictionary 会自动将你的键值转换成小写,并且没有控制这一情况的选项。
参见: http://social.msdn.microsoft.com/forums/en-US/netfxbcl/thread/59f38f98-6e53-431c-a6df-b2502c60e1e9/

3
StringDictionary 可以在 Properites.Settings 中使用,而 Dictionary<string, string> 则不行。因此,无论是否过时,StringDictionary 仍然有一些用途。 - jahu

4

StringDictionary 来自 .NET 1.1,并实现了 IEnumerable

Dictionary<string, string> 来自 .NET 2.0,并实现了 IDictionary<TKey, TValue>,IEnumerable<KeyValuePair<TKey, TValue>>, IEnumerable

StringDictionary 中,IgnoreCase 只适用于 Key

Dictionary<string, string> 对于 LINQ 很好用

        Dictionary<string, string> dictionary = new Dictionary<string, string>();
        dictionary.Add("ITEM-1", "VALUE-1");
        var item1 = dictionary["item-1"];       // throws KeyNotFoundException
        var itemEmpty = dictionary["item-9"];   // throws KeyNotFoundException

        StringDictionary stringDictionary = new StringDictionary();
        stringDictionary.Add("ITEM-1", "VALUE-1");
        var item1String = stringDictionary["item-1"];     //return "VALUE-1"
        var itemEmptystring = stringDictionary["item-9"]; //return null

        bool isKey = stringDictionary.ContainsValue("VALUE-1"); //return true
        bool isValue = stringDictionary.ContainsValue("value-1"); //return false

1
除了是一个比较“现代化”的类之外,我注意到字典与字符串字典相比,在内存效率上有很大的优势。

12
我们这里需要一些数据。 - Zonko

1
另一个相关的要点是(如果我理解错误请纠正),System.Collections.Generic.Dictionary 不能在应用程序设置 (Properties.Settings) 中使用,而 System.Collections.Specialized.StringDictionary 可以。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接