13

whenever i try to serialize the dictionary i get the exception:

System.ArgumentException: Type 
'System.Collections.Generic.Dictionary`2[[Foo.DictionarySerializationTest+TestEnum, Foo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]'
is not supported for serialization/deserialization of a dictionary,
keys must be strings or object

My Testcase is:

public class DictionarySerializationTest
{
  public enum TestEnum { A, B, C }
  //tried with numbers, too: public enum TestEnum { A = 1, B = 2, C = 3 }

  public void SerializationTest()
  {
    Dictionary<TestEnum, Int32> data = new Dictionary<TestEnum, Int32>();

    data.Add(TestEnum.A, 1);
    data.Add(TestEnum.B, 2);
    data.Add(TestEnum.C, 3);

    JavaScriptSerializer serializer = new JavaScriptSerializer();
    String result = serializer.Serialize(data);
    // Throws
  }

  public void SerializationToObjectTest()
  {
    Dictionary<object, Int32> data = new Dictionary<object, Int32>();

    data.Add(Enum.ToObject(typeof(TestEnum), TestEnum.A), 1);
    data.Add(Enum.ToObject(typeof(TestEnum), TestEnum.B), 2);
    data.Add(Enum.ToObject(typeof(TestEnum), TestEnum.C), 3);

    JavaScriptSerializer serializer = new JavaScriptSerializer();
    String result = serializer.Serialize(data);
    // Throws
  }

  public void SerializationStringTest()
  {
    Dictionary<String, Int32> data = new Dictionary<String, Int32>();

    data.Add(TestEnum.A.ToString(), 1);
    data.Add(TestEnum.B.ToString(), 2);
    data.Add(TestEnum.C.ToString(), 3);

    JavaScriptSerializer serializer = new JavaScriptSerializer();
    String result = serializer.Serialize(data);
    // Succeeds
  }

}

Of course i could use .ToString() whenever i enter something into the Dictionary but since it's used quite often in performance relevant methods i would prefer using the enum.

My only solution is using .ToString() and converting before entering the performance critical regions but that is clumsy and i would have to change my code structure just to be able to serialize the data.

Does anyone have an idea how i could serialize the dictionary as <Enum, Int32>?

I use the System.Web.Script.Serialization.JavaScriptSerializer for serialization.

UPDATE:

I switched to Dictionary<String, Int32> now and it works but i hope someone shows a solution as i don't really like using strings in place of a type safe enum.

  • possible duplicate of [How do I convert a dictionary to a JSON String in C#?](http://stackoverflow.com/questions/5597349/how-do-i-convert-a-dictionary-to-a-json-string-in-c) – Jim G. Mar 07 '14 at 16:39

5 Answers5

19

I know it's late, but maybe someone else can make use of it in the future. You can achieve what you need using LINQ:

Dictionary<TestEnum, Int32> data = new Dictionary<TestEnum, Int32>();

data.Add(TestEnum.A, 1);
data.Add(TestEnum.B, 2);
data.Add(TestEnum.C, 3);

JavaScriptSerializer serializer = new JavaScriptSerializer();
Dictionary<string, Int32> dataToSerialize = data.Keys.ToDictionary(p => p.ToString(), p => data[p]);
string dataSerialized = serializer.Serialize(dataToSerialize);
Michal B.
  • 5,676
  • 6
  • 42
  • 70
  • Not too late... Still helpful in 2016 – The Godfather Jul 29 '16 at 11:13
  • I would still recommend using Json.NET as it states in the JavaScriptSerializer class documentation: https://msdn.microsoft.com/en-us/library/system.web.script.serialization.javascriptserializer(v=vs.110).aspx – kimbaudi Nov 15 '17 at 13:58
6

Use Newtonsoft (Newtonsoft.Json.dll) to serialize the Dictionary object and you'd be fine. It's a popular third party library you would have to download and include in your project as a reference.

See example below:

var _validationInfos = new Dictionary<ImportField, ValidationInfo>();
var serializedData = JsonConvert.SerializeObject(_validationInfos);
Kwex
  • 3,992
  • 1
  • 35
  • 28
  • These days, even Microsoft recommends using the Newtonsoft JSON library: https://msdn.microsoft.com/en-us/library/system.web.script.serialization.javascriptserializer(v=vs.110).aspx – Mr47 Aug 22 '17 at 07:14
0

I think that you are having trouble because TestEnum is declared as a private enum. Try marking it as a public enum. The serializer needs to be able to find your enum via reflection in order to serialize it.

Also according to the Docs, the enums must have integer values. So you might want to write:

public enum TestEnum { A = 1, B = 2, C =3 }

Also, the docs say that this enum will just get mapped to its corresponding integer value during the serialization. So depending on what you are doing on the other end, Strings might be more expressive and easier to work with.

luke
  • 14,518
  • 4
  • 46
  • 57
  • Thanks for the suggestion, but changing the enum to public and adding integer values didn't change anything. –  May 23 '10 at 19:06
0

Exception says "keys must be strings or object" so try

data.Add(Enum.ToObject(typeof(TestEnum), TestEnum.A));
data.Add(Enum.ToObject(typeof(TestEnum), TestEnum.B));
data.Add(Enum.ToObject(typeof(TestEnum), TestEnum.C));

I did not test it though, just a guess.

Ekin Koc
  • 2,996
  • 20
  • 24
  • It doesn't seem to accept all object types, the error is still the same. Thanks for the suggestion though. –  May 23 '10 at 19:07
0

I’ve created JavaScriptSerializer extension DeserializeDictionary- see http://geekswithblogs.net/mnf/archive/2011/06/03/javascriptserializer-extension-deserializedictionarytkey-tvalue.aspx

public static Dictionary<TKey, TValue>  DeserializeDictionary<TKey, TValue>(this JavaScriptSerializer jss, string jsonText)
{
    var dictWithStringKey = jss.Deserialize<Dictionary<string,TValue>>(jsonText);
    var dict=dictWithStringKey.ToDictionary(de => jss.ConvertToType<TKey>(de.Key),de => de.Value);
        return dict;
}
Michael Freidgeim
  • 26,542
  • 16
  • 152
  • 170