将KeyValuePair自定义序列化为单个属性,而不是单独的“”;键“;以及“;值”;

本文关键字:单独 以及 序列化 自定义 KeyValuePair 单个 属性 | 更新日期: 2023-09-27 18:25:23

所以这是我的问题。我有一节课看起来像这样。。。

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 }
    //...
}

有没有一个编写器或序列化程序可以实现这一点?

将KeyValuePair自定义序列化为单个属性,而不是单独的“”;键“;以及“;值”;

如果您愿意编写自定义转换器类,Json.Net和内置的.NETJavaScriptSerializer都可以为您提供所需的输出。每个框架版本的转换器的接口都非常不同,但总体思想是相同的。我将在这个答案中演示两者。

使用Json.Net

在Json.Net中,您需要实现这样的JsonConverter类。CanConvert方法告诉Json.Net转换器可以处理什么类型的对象,而WriteJson方法则使用传递给该方法的JsonWriterJsonSerializer将每个实例转换为Json。

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不支持缩进输出。