Подтвердить что ты не робот

Проблемы с Json Serialize Dictionary <Enum, Int32>

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

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() всякий раз, когда я вводил что-то в словарь, но так как он довольно часто применялся в соответствующих методам производительности, я бы предпочел использовать перечисление.

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

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

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

UPDATE:

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

4b9b3361

Ответ 1

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

Ответ 2

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

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

var _validationInfos = new Dictionary<ImportField, ValidationInfo>();
var serializedData = JsonConvert.SerializeObject(_validationInfos);

Ответ 3

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

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

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

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

Ответ 4

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

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

Я не тестировал его, просто думаю.

Ответ 5

Ive создал расширение 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;
}