依赖于版本的Json反序列化

时间:2016-03-25 10:28:18

标签: c# json-deserialization

我正在寻找一种方法从Json进行反序列化,使用Json本身的数据依赖于版本。 我的目标是使用ServiceStack.Text.JsonDeserializer,但可以切换到另一个库。

例如,我想在JSON中为v1.0定义数据:

{
    version: "1.0"
    condition: "A < B"
}

然后,数据的下一个版本(比如说2.0)将是:

{
    version: "2.0"
    condition: ["A < B", "B = C", "B < 1"]
}

最后,我希望能够验证数据的版本,以了解如何正确反序列化JSON。

更新

看起来在已知产品中对版本相关的JSON(反)序列化没有任何隐式支持。

正确的解决方案似乎是通过(de)仅序列化版本部分来分割任务,然后使用隐式(de)序列化来获得正确的类型。

感谢所有分享有关问题的知识和想法的人。

4 个答案:

答案 0 :(得分:4)

您可以做的是以下内容:

  • 为要反序列化的数据对象创建一个包含version字段的基类,而不是其他任何内容。
  • 使不同版本的数据类成为此基类的派生类。
  • 反序列化数据对象时,首先将其反序列化为基类的实例 - 所以现在您有一个包含版本号的POCO对象。您可以使用它来决定您应该使用哪些派生数据类来反序列化数据(在最简单的情况下,您可以执行切换/案例并单独处理每个版本)

一个例子(使用System.Web.Script.Serialization.JavaScriptSerializer):

class BaseClass 
{
    public int version { get; set; }
}

class FirstVersion: BaseClass 
{
    public string condition { get; set; }
}

class SecondVersion: BaseClass
{
    public IEnumerable<string> condition { get; set; }
}

public void Deserialize (string jsonString)
{
    JavaScriptSerializer serializer = new JavaScriptSerializer();
    BaseClass myData = serializer.Deserialize<BaseClass>(jsonString);

    switch (myData.version) 
    {
        case 1:
            FirstVersion firstVersion = serializer.Deserialize<FirstVersion>(jsonString);
            // ...
            break;
        case 2:
            SecondVersion secondVersion = serializer.Deserialize<SecondVersion>(jsonString);
            // ...
            break;
    }
}

如您所见,此代码将数据反序列化两次 - 如果您正在处理大型数据结构,则可能会出现问题。如果您想不惜一切代价避免这种情况,您必须放弃静态类型或修改应用程序的数据模型。

以下是dynamic的样子:

public void Deserialize (string jsonString)
{
    JavaScriptSerializer serializer = new JavaScriptSerializer();
    dynamic myData = serializer.Deserialize<object>(jsonString);

    if (myData ["version"] == 1) {
        ...
    }
}

还可以选择编写自己的自定义JavaScriptConverter。这是更多的工作,但我很确定你可以实现你想要的东西,它看起来会更好。

要考虑的另一个建议是永远不要从JSON结构中删除属性。如果您需要修改属性,请保留旧属性并添加新属性 - 这样,旧代码始终可以从较新的代码中读取数据。当然,如果您经常修改数据结构,这可能会很快失控......

在Java中,您可以使用Google的GSON库,因为它有built-in support for versioning。我没有调查它,但它是open source,如果它对你真的很重要,我猜你可以将实现移植到另一种语言。

答案 1 :(得分:1)

我建议您使用json.net,它允许您添加可用于版本控制的自定义类型转换。

问题不是序列化,因为它总是使用当前架构。问题是当客户端使用与接收对象的服务器不同的类型版本时。

您需要做的是在类型转换器中以编程方式检查版本并自行转换值(在这种情况下将字符串转换为数组)。

文档:http://www.newtonsoft.com/json/help/html/CustomJsonConverter.htm

答案 2 :(得分:0)

您可能想要使用NewtonSoft.Json NuGET package

这是.NET社区中的一种标准。它通常也被称为Json.NET

您可以像这样使用它(官方网站example):

Product product = new Product();

product.Name = "Apple";
product.ExpiryDate = new DateTime(2008, 12, 28);
product.Price = 3.99M;
product.Sizes = new string[] { "Small", "Medium", "Large" };

string output = JsonConvert.SerializeObject(product);
//{
//  "Name": "Apple",
//  "ExpiryDate": "2008-12-28T00:00:00",
//  "Price": 3.99,
//  "Sizes": [
//    "Small",
//    "Medium",
//    "Large"
//  ]
//}

Product deserializedProduct = JsonConvert.DeserializeObject<Product>(output);

答案 3 :(得分:-1)

看看

System.Web.Script.Serialization.JavaScriptSerializer

样品

var ser = new JavaScriptSerializer();
var result = (IReadOnlyDictionary<string, object>)ser.DeserializeObject(json);

if(result["version"] == "1.0")
{
    // You expect a string for result["condition"]
}
else
{
    // You expect an IEnumerable<string> for result["condition"]
}