将KeyValuePair自定义序列化为单个属性,而不是单独的" key"和"价值"

时间:2014-10-01 13:47:22

标签: c# json serialization

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

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

那里有作家或序列号可以做到这一点吗?

1 个答案:

答案 0 :(得分:2)

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

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