使用JSON.NET使用IEnumerable反序列化对象

时间:2018-09-05 12:22:14

标签: c# json json.net json-deserialization

考虑以下json和模型:

{
    "Reference": "Bay House 22",
    "Appliances": [
        {
            "Reference": "Kitchen Appliance 1",
            "ApplianceType": "0",
            "NumberOfSlots": 4
        },
        {
            "Reference": "Kitchen Appliance 2",
            "ApplianceType": "1",
            "Capacity": 1500
        }
    ]
}

public class HouseModel
{
    public String Reference { get; set; }
    [JsonConverter(typeof(ApplianceModelConverter))]
    public IEnumerable<IApplianceModel> Appliances { get; set; }
}

public interface IApplianceModel
{
    String Reference { get; set; }
    ApplianceType ApplianceType { get; set; } // this is an enum
}

public class ToasterModel : IApplianceModel
{
    public String Reference { get; set; }
    public ApplianceType ApplianceType { get; set; }

    public Int32 NumberOfSlots { get; set; }
}

public class KettleModel : IApplianceModel
{
    public String Reference { get; set; }
    public ApplianceType ApplianceType { get; set; }

    public Int32 Capacity { get; set; }
}

我正在尝试使用自定义json转换器反序列化IEnumerable,该IEnumerable可以是ToasterKettle。这里的想法是,一旦我了解了ApplianceType,就可以通过查看json返回具体类型。我一直在关注this stackoverflow帖子,尝试使其正常运行,但没有成功。

这是转换器代码:

public abstract class JsonCreationConverter<T> : JsonConverter
{
    protected abstract T Create(Type objectType, JObject jObject);

    public override Boolean CanConvert(Type objectType)
    {
        return typeof(T).IsAssignableFrom(objectType);
    }

    public override Boolean CanWrite
    {
        get { return false; }
    }

    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
        T target = Create(objectType, jObject);

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

        return target;
    }
}

public class ApplianceModelConverter: JsonCreationConverter<IApplianceModel>
{
    protected override IApplianceModel Create(Type objectType, JObject jObject)
    {
        if (jObject["applianceType "] == null)
        {
            throw new ArgumentException("Missing ApplianceType");
        }

        ApplianceType applianceType = jObject.Value<ApplianceType>();

        switch (applianceType )
        {
            case ApplianceType.Kettle:
                return new KettleModel();
            case ApplianceType.Toaster: 
                return new ToasterModel();
            default:
                throw new InvalidEnumArgumentException("ApplianceType not supported");
        }
    }
}

当前执行此行时引发异常:JObject jObject = JObject.Load(reader);中的JsonCreationConverter

  

Newtonsoft.Json.JsonReaderException:'从中读取JObject时出错   JsonReader。当前JsonReader项不是对象:StartArray。路径   “家电”

我想它已经到IEnumerable了,只是失败了,我在这里做什么错了?

1 个答案:

答案 0 :(得分:2)

注释此行代码

    public class HouseModel
{
    public String Reference { get; set; }
    //[JsonConverter(typeof(ApplianceModelConverter))] //=> You don't need this
    public IEnumerable<IApplianceModel> Appliances { get; set; }
}

也将Create方法更改为此

 protected override IApplianceModel Create(Type objectType, JObject jObject)
    {
        if (jObject["ApplianceType"] == null) //case sensitive
        {
            throw new ArgumentException("Missing ApplianceType");
        }

        //ApplianceType applianceType = jObject.Value<ApplianceType>(); //this might throw invalid cast exception
        ApplianceType applianceType = jObject["ApplianceType"].ToObject<ApplianceType>();


        switch (applianceType)
        {
            case ApplianceType.Kettle:
                return new KettleModel();
            case ApplianceType.Toaster:
                return new ToasterModel();
            default:
                throw new InvalidEnumArgumentException("ApplianceType not supported");
        }
    }

如果我们正在使用此方法反序列化

string json = "{\"Reference\": \"Bay House 22\",\"Appliances\": [{\"Reference\": \"Kitchen Appliance 1\",\"ApplianceType\": \"0\",\"NumberOfSlots\": 4},{\"Reference\": \"Kitchen Appliance 2\",\"ApplianceType\": \"1\",\"Capacity\": 1500}]}";

HouseModel houseModels = JsonConvert.DeserializeObject<HouseModel>(json, new ApplianceModelConverter());