81

Does anyone have any idea what the practical differences are between the System.Collections.Specialized.StringDictionary object and System.Collections.Generic.Dictionary?

I've used them both in the past without much thought as to which would perform better, work better with Linq, or provide any other benefits.

Any thoughts or suggestions as to why I should use one over the other?

Scott Ivey
  • 40,768
  • 21
  • 80
  • 118

7 Answers7

96

Dictionary<string, string> is a more modern approach. It implements IEnumerable<T> and it's more suited for LINQy stuff.

StringDictionary is the old school way. It was there before generics days. I would use it only when interfacing with legacy code.

Mehrdad Afshari
  • 414,610
  • 91
  • 852
  • 789
  • You should benchmark to see which performs better for your special situation. I don't expect a noticeable performance difference. I recommend using `Dictionary` for all new code (unless you need to target 1.1). – Mehrdad Afshari Dec 07 '09 at 14:03
  • 2
    @thecoop no hard data to present from my side now, but once when I did test for speed `StringDictionary` performed worse (though all that wont matter mostly). To be honest in fact, earlier I had the notion that `StringDictionary` was some sorta specialized collection meant for speeding things when `string` was the key, and to my great surprise when it performed worse in my testing, I googled it up only to learn it is nongeneric – nawfal Jan 30 '13 at 19:44
  • 1
    @nawfal I think it's slower because StringDictionary is case-insensitive by default. If you create a Dictionary with case-insensitive key comparer then I believe performance will be the same – phuclv Nov 30 '19 at 06:18
43

Another point.

This returns null:

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

This throws an exception:

Dictionary<string, string> dic = new Dictionary<string, string>();
return dic["Hey"];
joshcomley
  • 28,099
  • 24
  • 107
  • 147
  • The "throws an exception" *feature* of`Dictionary<>` means i can never use `[]`. Use StringDictionary has cleaned up much of my code. – James Curran Jul 14 '17 at 17:59
  • 1
    @James I'm a little late but you should probably use TryGetValue. – Şafak Gür Nov 28 '17 at 13:46
  • @ŞafakGür -- I *do* use TryGetValue() -- because I can never use `[ ]` because it throws an exception. (StringDictionary only solves this for one type of Dictionaries) – James Curran Nov 29 '17 at 22:36
  • @James, I believe throwing an exception for non-existent keys is a better API choice since null is allowed as a dictionary value. This way you can distinguish between a key that does not exist from one whose value is null. – Şafak Gür Nov 30 '17 at 07:17
  • 1
    @ŞafakGür this is true -- if your need is for a dictionary which a) should always have all values, b) can contain nulls and c) those null means something diffeent than "no value".. However,in a dictionary "no value" is usually represented by the key not being there. However, the real reason Dictionary<> throw an exception, is because the value could be a value type (and therefore, can't be represented with a null). – James Curran Nov 30 '17 at 19:39
  • 1
    The reason a generic dictionary throws when the key doesn't exist is because if it returned `default(TValue)` instead, it would be impossible to distinguish between the dictionary having an item with a `Value` of `default(TValue)` or containing no `KeyValuePair` matching the `Key`. This is why using `TryGetValue` makes sense most of the time. Do note that it is possible to get back the behavior that *doesn't* throw if the `Key` doesn't exist by using `((IDictionary)dic)["Hey"];`, but you should only do this for reference types (if ever). – NightOwl888 Mar 14 '22 at 17:07
41

I think StringDictionary is pretty much obsolete. It existed in v1.1 of the framework (before generics), so it was a superior version at the time (compared to the non-generic Dictionary), but at this point, I don't believe there are any specific advantages to it over Dictionary.

However, there are disadvantages to StringDictionary. StringDictionary lower-cases your key values automatically, and there are no options for controlling this.

See:

http://social.msdn.microsoft.com/forums/en-US/netfxbcl/thread/59f38f98-6e53-431c-a6df-b2502c60e1e9/

Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • 3
    `StringDictionary` can be used in `Properites.Settings` while `Dictionary` cannot. So obsolete or not, there is still some use for `StringDictionary`. – jahu Feb 05 '18 at 11:41
41

As Reed Copsey pointed out, StringDictionary lower-cases your key values. For me this was totatlly unexpected, and is a show-stopper.

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);
    }
}

I'm adding this reply to draw more attention to this huge difference, which IMO is more important than the modern vs. old-school difference.

Jeff Roe
  • 3,147
  • 32
  • 45
  • 5
    If for some reason one want the same behaviour with Dictionary this can be used: Dictionary ht = new Dictionary(StringComparer.OrdinalIgnoreCase); ht.Add("Bob", "ff"); ht.Add("bob", "ff"); // throws exception – osexpert Jan 18 '16 at 08:50
4

StringDictionary comes from .NET 1.1 and implements IEnumerable

Dictionary<string, string> comes from .NET 2.0 and implements IDictionary<TKey, TValue>,IEnumerable<KeyValuePair<TKey, TValue>>, IEnumerable

IgnoreCase is only set for Key in StringDictionary

Dictionary<string, string> is good for 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
ArekBee
  • 311
  • 2
  • 6
1

Another relevant point is that (correct me if I'm wrong here) System.Collections.Generic.Dictionary isn't able to be used in application settings (Properties.Settings) whereas System.Collections.Specialized.StringDictionary is.

Matt Lyons-Wood
  • 931
  • 11
  • 17
1

Besides being a more "modern" class, I noticed that Dictionary is more memory efficient than StringDictionary by a large margin.

Daniel
  • 1,195
  • 9
  • 13