Проблемы с Json Serialize Dictionary <Enum, Int32> - PullRequest
13 голосов
/ 23 мая 2010

всякий раз, когда я пытаюсь сериализовать словарь, я получаю исключение:

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

Мой тестовый случай:

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
  }

}

Конечно, я мог бы использовать .ToString () всякий раз, когда вводил что-то в словарь, но так как это довольно часто используется в методах, связанных с производительностью, я бы предпочел использовать enum.

Моим единственным решением является использование .ToString () и преобразование перед входом в критические области производительности, но это неуклюже, и мне придется изменить структуру кода, чтобы иметь возможность сериализовать данные.

Кто-нибудь знает, как я мог бы сериализовать словарь как <Enum, Int32>?

Я использую System.Web.Script.Serialization.JavaScriptSerializer для сериализации.

UPDATE:

Я перешел на Dictionary<String, Int32> сейчас, и это работает, но я надеюсь, что кто-то покажет решение, так как я не очень люблю использовать строки вместо перечисления типа safe.

Ответы [ 5 ]

18 голосов
/ 07 февраля 2012

Я знаю, что уже поздно, но, возможно, кто-то другой сможет использовать это в будущем. Вы можете достичь того, что вам нужно, используя 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);
6 голосов
/ 23 мая 2012

Используйте Newtonsoft (Newtonsoft.Json.dll) для сериализации объекта Dictionary, и все будет в порядке.Это популярная сторонняя библиотека, которую вы должны загрузить и включить в свой проект в качестве справки.

См. Пример ниже:

var _validationInfos = new Dictionary<ImportField, ValidationInfo>();
var serializedData = JsonConvert.SerializeObject(_validationInfos);
0 голосов
/ 23 мая 2010

Исключение говорит, что "ключи должны быть строками или объектом", поэтому попробуйте

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

Хотя я не проверял это, только предположение.

0 голосов
/ 03 июня 2011

Я создал расширение JavaScriptSerializer DeserializeDictionary - см. 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;
}
0 голосов
/ 23 мая 2010

Я думаю, что у вас проблемы, потому что TestEnum объявлен как private enum.Попробуйте пометить его как public enum.Сериализатору необходимо иметь возможность найти ваше перечисление с помощью отражения, чтобы сериализовать его.

Также в соответствии с Документами , перечисления должны иметь целочисленные значения.Поэтому вы можете написать:

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

Кроме того, в документах говорится, что это перечисление будет просто сопоставлено с соответствующим ему целочисленным значением во время сериализации.Поэтому в зависимости от того, что вы делаете на другом конце, String s может быть более выразительным и с ним легче работать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...