Пользовательская сериализация KeyValuePair как отдельное свойство вместо отдельных «ключ» и «значение»

1

Так вот моя проблема. У меня есть класс, который выглядит примерно так...

public class Record
{
    public string Name { get; set; }
    public KeyValuePair<string, object> Details { get; set; }
}

И вот базовый пример того, как может выглядеть экземпляр...

var root = new Record
{
    Name = "Root",
    Details = new KeyValuePair<string, object>("TestSerialization", 
        new List<KeyValuePair<string, object>>
        {
            new KeyValuePair<string, object>("IsChild", true),
            new KeyValuePair<string, object>("Child1", "Another KV pair")
        })
};

Я хочу сериализовать этот объект в JSON, но я хочу немного изменить процесс. Поэтому, когда я сериализую этот объект, я хочу, чтобы JSON выглядел примерно так...

{
    "Name" : "Root",
    "Details" : 
    {
        "TestSerialization" : 
        [
            { "IsChild" : true },
            { "Child1" : "Another KV pair" }
        ]
    }
}

Но похоже, что большинство сериализаторов сериализуют пары ключ-значение в нечто подобное...

{
    //...
    { "key" : "IsChild", "value" : true }
    //...
}

Есть ли писатель или сериализатор, который может это сделать?

  • 0
    Вы можете напрямую использовать JavaScriptSerializer для сериализации, посмотрите пример, который я привел.
  • 0
    JavaScriptSerializer и JsonConvert дали один и JsonConvert же результат, я думаю, что лучше использовать сторонний DDL. JsonConvert том, что если в JSS есть основная функциональность, то зачем переходить на сторонние DLL, что скажете?
Показать ещё 3 комментария
Теги:
serialization

1 ответ

2
Лучший ответ

И Json.Net, и встроенный.NET JavaScriptSerializer могут предоставить вам нужный вам результат, если вы захотите написать собственный класс конвертера. Интерфейс для каждой каркасной версии конвертера совсем другой, но общая идея такая же. Я продемонстрирую оба в этом ответе.

Использование Json.Net

В Json.Net вам нужно будет реализовать класс JsonConverter. Метод CanConvert сообщает Json.Net, какой тип объектов (ов) может обрабатывать конвертер, а метод WriteJson обрабатывает преобразование каждого экземпляра в JSON с использованием JsonWriter и JsonSerializer переданных методу.

class KvpConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(KeyValuePair<string, object>);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var kvp = (KeyValuePair<string, object>)value;
        writer.WriteStartObject();
        writer.WritePropertyName(kvp.Key);
        serializer.Serialize(writer, kvp.Value);
        writer.WriteEndObject();
    }

    public override bool CanRead
    {
        get { return false; }
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

Вот демонстрация, показывающая, как использовать преобразователь при сериализации:

class Program
{
    static void Main(string[] args)
    {
        var root = new Record
        {
            Name = "Root",
            Details = new KeyValuePair<string, object>("TestSerialization", 
                new List<KeyValuePair<string, object>>
                {
                    new KeyValuePair<string, object>("IsChild", true),
                    new KeyValuePair<string, object>("Child1", "Another KV pair")
                })
        };

        var settings = new JsonSerializerSettings();
        settings.Converters.Add(new KvpConverter());
        settings.Formatting = Formatting.Indented;

        string json = JsonConvert.SerializeObject(root, settings);
        Console.WriteLine(json);
    }
}

public class Record
{
    public string Name { get; set; }
    public KeyValuePair<string, object> Details { get; set; }
}

Вывод:

{
  "Name": "Root",
  "Details": {
    "TestSerialization": [
      {
        "IsChild": true
      },
      {
        "Child1": "Another KV pair"
      }
    ]
  }
}

Использование JavaScriptSerializer

Версия.Net-конвертера называется JavaScriptConverter. Подобно Json.Net, свойство SupportedTypes сообщает JavaScriptSerializer какие типы объектов обрабатывает конвертер, в то время как метод Serialize отвечает за изменение формы вывода. Основное отличие состоит в том, что в Serialize вы не имеете прямого контроля над выходом JSON; вместо этого вы создаете и возвращаете IDictionary<string, object> который сериализатор затем сериализуется вместо исходного объекта, который вы конвертируете. Так что не такая гибкая, как Json.Net, но этого достаточно, чтобы получить то, что нам нужно в этом случае. Вот как выглядит код для JavaScriptConverter:

class KvpJavaScriptConverter : JavaScriptConverter
{
    public override IEnumerable<Type> SupportedTypes
    {
        get { return new List<Type> { typeof(KeyValuePair<string, object>) }; }
    }

    public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
    {
        KeyValuePair<string, object> kvp = (KeyValuePair<string, object>)obj;
        Dictionary<string, object> dict = new Dictionary<string, object>();
        dict.Add(kvp.Key, kvp.Value);
        return dict;
    }

    public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

Вот обновленный демо-код:

class Program
{
    static void Main(string[] args)
    {
        var root = new Record
        {
            Name = "Root",
            Details = new KeyValuePair<string, object>("TestSerialization", 
                new List<KeyValuePair<string, object>>
                {
                    new KeyValuePair<string, object>("IsChild", true),
                    new KeyValuePair<string, object>("Child1", "Another KV pair")
                })
        };

        var serializer = new JavaScriptSerializer();
        serializer.RegisterConverters(
            new List<JavaScriptConverter> { new KvpJavaScriptConverter() });
        string json = serializer.Serialize(root);
        Console.WriteLine(json);
    }
}

Результат такой же, как и для демонстрации Json.Net, за исключением того, что JavaScriptSerializer не поддерживает вывод с отступом.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню