6

I am serializing a Dictionary to XML. When I create a new dictionary I use the constructor to provide EqualityComparer without casing for instance

var tabs = new Dictionary<string,Tab>(StringComparer.OrdinalIgnoreCase);

I then serialize to XML and when I deserialize information about casing is lost - the deserialization is made to the Dictionary with GenericEqualityComparer, which apparently is case sensitive, because it doesn't find my keys if they are not cased correctly.

Any ideas how can I change it?

One way would be to create a new dictionary and copy the data from the deserialized over to the new one but this seems troublesome.

UPDATE:

The deserialization worked the whole time it is just that it deserializes the serialized Dictionary to one that does not use case insensitive keys.

mare
  • 13,033
  • 24
  • 102
  • 191
  • Does this problem occur when you use DataContract? – Steven Sudit Aug 09 '10 at 13:43
  • yes, the class that contains a property of type Dictionary is marked as DataContract and this property is marked as DataMbember, if that's what you wanted to know – mare Aug 09 '10 at 13:47
  • Yes, it was, but now that you figured out that it works in .NET 4.0, there's nothing for me to follow up on. Congrats on solving your own problem. – Steven Sudit Aug 09 '10 at 15:46
  • Actually no, the serializing/deserializing worked the whole time, it is the Deserialization to case insensitive Dictionary that is not working. Still. – mare Aug 09 '10 at 19:27
  • I just checked .NET 4.0 using Reflector and it's very clear that the `OnDeserialization` method handles the comparer properly. Have you tried taking advantage of `SerializableAttribute`? – Steven Sudit Aug 09 '10 at 20:00

4 Answers4

4

I know this question is quite old, but I recently found myself searching for how to do this.

Using .Net4 (like @mare said), you can create some really nice extension methods to make this a breeze. Check out https://stackoverflow.com/a/5941122/435460 for a nice and simple implementation.

After a lot of digging, this worked like a charm for me.

Community
  • 1
  • 1
JesseBuesking
  • 6,496
  • 4
  • 44
  • 89
3

Edit:

Per the comments, it appears this approach may be outdated in .NET 4.

End Edit

Dictionaries happen to require a little help to serialize and deserialize.

Here is a good example of an XML Serializable dictionary:

http://weblogs.asp.net/pwelter34/archive/2006/05/03/444961.aspx

You can make it case insensitive by changing the class declaration and adding a constructor, and tweaking a line.

** EDIT: Corrected syntax error below. /EDIT**

public class SerializableDictionary<TValue>
    : Dictionary<string, TValue>, IXmlSerializable
{
    public SerializableDictionary()
        : base(StringComparer.InvariantCultureIgnoreCase)
    {
    }

    // ...
}

Change the line this.Add(key, value); to this[key] = value;.

At any rate, you may need to massage some of the details, but this should get you well on the road.

kbrimington
  • 25,142
  • 5
  • 62
  • 74
  • Working with .NET 4 it seems that the generic Dictionary is serializable, as it is working for me. I am not sure if implementing a solution from 2006 is advisable, given that the new Dictionary implementation or the DataContractSerializer's implementation supports Dictionary serialization/deserialization out-of-the-box. – mare Aug 09 '10 at 13:51
  • @mare: Hey, that's good news! Please consider updating the tag to .NET 4, and I'll place an edit on my post. – kbrimington Aug 09 '10 at 13:58
  • Does not compile since `Type parameter declaration must be an identifier not a type` for `string` in `SerializableDictionary`. – JoeBilly Aug 12 '13 at 09:45
  • @Joe - Correct. Remove `string, ` from the first line. Regardless, it is an incomplete implementation that is superseded by the last few versions of the .NET framework. I, personally, prefer the accepted answer. – kbrimington Aug 19 '13 at 23:47
  • Yep but in 3.5 this is the better implementation afaik. Don't like the `new Dictionay<>(IDictionary)` because the constructor do a `foreach` under the covers, bah :( – JoeBilly Aug 20 '13 at 09:42
1

You just have to wrap up your new dictionary in the Constructor:

Dictionary<string, Tab> tabs ;
tabs = new Dictionary<string, Tab>((Dictionary<string, Tab>)serializer.ReadObject(reader),StringComparer.OrdinalIgnoreCase);
Littm
  • 4,923
  • 4
  • 30
  • 38
victoro
  • 11
  • 1
1

An old question I realize, but was just digging through the source to Dictionary and noticed that it should in fact serialize the Comparer:

info.AddValue(ComparerName, comparer, typeof(IEqualityComparer<tkey>));

Then in the implementation of IDeserializationCallback.OnDeserialization it retrieves the Comparar:

comparer = (IEqualityComparer<tkey>)m_siInfo.GetValue(ComparerName, typeof(IEqualityComparer<tkey>));

Classes implementing the interface IDeserializationCallback specify a method that should be executed after the an instance has been deserialized, but before its returned to your code.

Ref: Dictionary.cs GetObjectData and OnDeserialization methods

Joey Ciechanowicz
  • 3,345
  • 3
  • 24
  • 48