6

I want to save some pairs in a dictionary.

At the end I want to serialize the dictionary to a JSON object. I then print the JSON content. I want the pairs to be printed in the same order they were entered in the dictionary.

At first I used an ordinary dictionary. But then I thought the order might not be kept. Then I migrated to OrderedDictionary, but it doesn't use Generic, meaning it's not type-safe.

Do you have any other good-practice solution for me?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Elad Benda
  • 35,076
  • 87
  • 265
  • 471

4 Answers4

7

If you can't find a replacement, and you don't want to change the collection type you're using, the simplest thing may be to write a type-safe wrapper around OrderedDictionary.

It is doing the same work you're doing now, but the un-type-safe code is much more limited, just in this one class. In this class, we can rely on the backing dictionary only having TKey and TValue types in it, because it could only have been inserted from our own Add methods. In the rest of your application, you can treat this as a type-safe collection.

public class OrderedDictionary<TKey, TValue> : IDictionary<TKey, TValue> {
    private OrderedDictionary backing = new OrderedDictionary();

    // for each IDictionary<TKey, TValue> method, simply call that method in 
    // OrderedDictionary, performing the casts manually. Also duplicate any of 
    // the index-based methods from OrderedDictionary that you need.

    void Add(TKey key, TValue value)
    {
        this.backing.Add(key, value);
    }

    bool TryGetValue(TKey key, out TValue value)
    {
        object objValue;
        bool result = this.backing.TryGetValue(key, out objValue);
        value = (TValue)objValue;
        return result;
    }

    TValue this[TKey key]
    {
        get
        {
            return (TValue)this.backing[key];
        }
        set
        {
            this.backing[key] = value;
        }
    }
}
David Yaw
  • 27,383
  • 4
  • 60
  • 93
  • 2
    This should be the accepted answer. Also see http://stackoverflow.com/questions/2629027/no-generic-implementation-of-ordereddictionary and http://www.codeproject.com/Articles/18615/OrderedDictionary-T-A-generic-implementation-of-IO. – Jordan Rieger Oct 18 '13 at 22:36
  • 1
    Ah, and the boxing penalties... – nawfal Oct 31 '13 at 07:03
  • For those not familiar with Boxing penalties see: https://www.codingblocks.net/programming/boxing-and-unboxing-7-deadly-sins/ – AnthonyVO Sep 04 '20 at 17:37
3

Don't use a dictionary if the order of the values are important. The things that come off the top of my head are a SortedDictionary or a List<KeyValuePair>.

Peter Olson
  • 139,199
  • 49
  • 202
  • 242
  • 1
    Right. `Dictionary` won't preserve the order. `List` is the key here. – Jim Mischel Mar 23 '11 at 20:43
  • 7
    `SortedDictionary` doesn't preserve the order of insertion, it imposes a sorted order ! – digEmAll Mar 23 '11 at 20:49
  • @digEmAll You're right. I wasn't completely sure what the OP wanted. – Peter Olson Mar 23 '11 at 20:56
  • 8
    @PeterOlson, I disagree that you shouldn't use a dictionary if the order is important. The OP's requirement is valid. A dictionary's main benefits are enforcement of uniqueness and fast key lookup. I can envision a situation where you want those benefits, but you also want to maintain a list of the original order of insertion. You could do this yourself separately, but OrderedDictionary does it for you internally. The only thing missing is type safety, probably because MS just never bothered to add it. See http://stackoverflow.com/questions/2629027/ – Jordan Rieger Oct 18 '13 at 22:53
  • There are many usage patterns where dictionaries will have items added but never removed. For a dictionary using chain-bucket hashing the extra cost to maintain items in insertion order is minimal (using an index-linked list within an array is apt to be more efficient than using a reference-linked list of discrete dictionary-entry objects). If one wishes to test whether two such dictionaries match, and it is likely that if they match they would have had items added in the same order, the ability to enumerate the items in sequence may enable a useful optimization. – supercat Aug 12 '15 at 16:06
  • To all of the above. An ordered dictionary does indeed preserve the order of insertion as per it's name. This has not changed since this post was made and thus is still valid today. – John Stock May 05 '17 at 14:42
1

If you are okay to sort it based on the key then a SortedDictionary may suit you. AFAIK there is no generic implementation of OrderedDictionary unless you implement one.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
WorldIsRound
  • 1,544
  • 10
  • 15
0

I had to rewrite David Yaw's TryGetValue from his excellent suggestion since OrderedDictionary does not have a TryGetValue method. Here is my modification.

    bool TryGetValue(TKey key, out TValue value)
    {
        object objValue;
        value = default(TValue);
        try
        {
            objValue = this.backing[key];
            value = (TValue)objValue;
        }
        catch
        {
            return false;
        }
        return true;
    }
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Cathy
  • 67
  • 3