当前位置: 首页 > 面试题库 >

使用Json.NET将异构JSON数组反序列化为协变List <>

翁凯定
2023-03-14
问题内容

我有一个JSON数组,其中包含具有不同属性的不同类型的对象。属性之一称为“类型”,它确定数组项的类型。这是我的数据示例:

   [{
        type : "comment",
        text : "xxxx"
    }, {
        type : "code",
        tokens : [{
                type : "ref",
                data : "m"
            }, {
                type : "operator",
                data : "e"
            }
        ]
    }, {
        type : "for",
        boundLocal : {
            type : "local",
            name : "i",
            kind : "Number"
        },
        upperBound : {
            type : "ref",
            tokens : [{
                    type : "operator",
                    data : "3"
                }, {
                    type : "operator",
                    data : "0"
                }
            ]
        },
        body : [{
                type : "code",
                tokens : [{
                        type : "ref",
                        data : "x"
                    }
                ]
            }, {
                type : "code",
                tokens : [{
                        type : "ref",
                        data : "y"
                    }
                }
                ]
        ]
    ]

为了将这些对象映射到我的.Net实现中,我定义了一组类:一个基类和几个子类(具有复杂的层次结构,具有4个“世代”)。这只是这些类的一个小示例:

public abstract class TExpression
{
    [JsonProperty("type")]
    public string Type { get; set; }
}

public class TComment : TExpression
{
    [JsonProperty("text")]
    public string Text { get; set; }
}

public class TTokenSequence : TExpression
{
    [JsonProperty("tokens")]
    public List<TToken> Tokens { get; set; }
}

我想达到的目的是能够将此数组反序列化为协变通用列表,声明为:

List<TExpression> myexpressions = JsonConvert.DeserializeObject<List<TExpression>>(aststring);

此列表应包含从TExpression继承的适当子类的实例,因此稍后我可以在代码中使用以下代码:

foreach(TExpression t in myexpressions)
{
    if (t is TComment) dosomething;
    if (t is TTokenSequence) dosomethingelse;
}

如何使用JSON.NET达到目标?


问题答案:

这是使用CustomCreationConverter的示例。

public class JsonItemConverter :  Newtonsoft.Json.Converters.CustomCreationConverter<Item>
{
    public override Item Create(Type objectType)
    {
        throw new NotImplementedException();
    }

    public Item Create(Type objectType, JObject jObject)
    {
        var type = (string)jObject.Property("valueType");
        switch (type)
        {
            case "int":
                return new IntItem();
            case "string":
                return new StringItem();
        }

        throw new ApplicationException(String.Format("The given vehicle type {0} is not supported!", type));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        // Load JObject from stream
        JObject jObject = JObject.Load(reader);

        // Create target object based on JObject
        var target = Create(objectType, jObject);

        // Populate the object properties
        serializer.Populate(jObject.CreateReader(), target);

        return target;
    }
}

public abstract class Item
{
    public string ValueType { get; set; }

    [JsonProperty("valueTypeId")]
    public int ValueTypeId { get; set; }

    [JsonProperty("name")]
    public string Name { get; set; }

    public new virtual string ToString() { return "Base object, we dont' want base created ValueType=" + this.ValueType + "; " + "name: " + Name; }
}

public class StringItem : Item
{
    [JsonProperty("value")]
    public string Value { get; set; }

    [JsonProperty("numberChars")]
    public int NumberCharacters { get; set; }

    public override string ToString() { return "StringItem object ValueType=" + this.ValueType + ", Value=" + this.Value + "; " + "Num Chars= " + NumberCharacters; }

}

public class IntItem : Item
{
    [JsonProperty("value")]
    public int Value { get; set; }

    public override string ToString() { return "IntItem object ValueType=" + this.ValueType + ", Value=" + this.Value; }
}

class Program
{
    static void Main(string[] args)
    {
        // json string
        var json = "[{\"value\":5,\"valueType\":\"int\",\"valueTypeId\":1,\"name\":\"numberOfDups\"},{\"value\":\"some thing\",\"valueType\":\"string\",\"valueTypeId\":1,\"name\":\"a\",\"numberChars\":11},{\"value\":2,\"valueType\":\"int\",\"valueTypeId\":2,\"name\":\"b\"}]";

        // The above is deserialized into a list of Items, instead of a hetrogenous list of
        // IntItem and StringItem
        var result = JsonConvert.DeserializeObject<List<Item>>(json, new JsonItemConverter());

        foreach (var r in result)
        {
            // r is an instance of Item not StringItem or IntItem
            Console.WriteLine("got " + r.ToString());
        }
    }
}


 类似资料:
  • 问题内容: 我有一个带有JSON数组的有效JSON对象。JSON数组没有花括号,并且包含逗号分隔的混合类型列表。看起来像这样: 我创建了一个反映JSON结构的类,为复杂数组提供了一个List: 我也用列表列表进行了测试: 子模型如下所示: 在我的program.cs文件中,我正在反序列化如下: 当我运行该程序时,子对象(Rows)始终为。我究竟做错了什么? 问题答案: Json.Net没有将数组自

  • 问题内容: 我的JSON有点弱,所以我需要一些帮助。 我正在尝试反序列化用户的JSON: 放入我用属性装饰的对象中: 我得到以下异常: Newtonsoft.Json.JsonSerializationException:在JSON中找不到必需的属性’user_id’。 这是因为JSON对象是一个数组吗?如果是这样,如何将其反序列化为一个User对象? 提前致谢! 问题答案: 正如Alexandr

  • 问题内容: 我正在尝试将json数据反序列化为模型类,但是失败了。这是我的工作: 这是我的模型的样子: 您可以看到我到达这里的Json:http : //api.worldbank.org/incomeLevels/LIC/countries? format=json 这是我得到的错误: 无法将JSON数组反序列化为“ Mvc4AsyncSample.Models.CountryModel”类型。

  • 问题内容: 我想将二维数组反序列化为.net对象的集合。原因是,数组语法将使我的用户更容易在输入文件中使用。所以我只想将数组的索引映射到目标类型的特定属性。 EG具有: 我会得到一个Person的两个实例: 其中内部数组的索引0映射到,索引1映射到,索引2映射到; 有没有一种扩展Json.NET的方法,以便我可以在反序列化期间进行映射,从而隐藏实现细节?我一直在玩一个自定义,但是我没有找到太多关于

  • 问题内容: 我正在尝试将一些JSON数据反序列化为应用程序的对象。到现在为止还不错,因为JSON数据上的属性是静态的(带有值的键)。现在,我得到了一个结果,其中的关键是动态数据。 这是一个示例JSON网址: http://en.wikipedia.org/w/api.php?action=query&format=json&pageids=6695&prop=info 由此产生的JSON是: 好的

  • 问题内容: 我在反序列化一些json数据,获取InvalidCastExceptions之类的问题。 谁能指出我正确的方向? 这是我要反序列化的json; [{“ OrderId”:0,“名称”:“摘要”,“ MaxLen”:“ 200”},{“ OrderId”:1,“名称”:“详细信息”,“ MaxLen”:“ 0”}] 这是我的代码; 问题答案: OrderId是json中的一个Int(请注