JSON.NET反序列化列表<;TypeX>;名为TypeX的属性

本文关键字:TypeX gt 名为 属性 lt NET 反序列化 列表 JSON | 更新日期: 2023-09-27 17:59:48

我们目前正在实现一个基于JSON的通信协议(因此我们无法更改数据合约名称/类型),在反序列化包含属性的类时遇到问题:"无法将当前JSON数组(例如[1,2,3])反序列化为类型'…PriceScheme'…'

public class RootElement {
   public List<PriceScheme> PriceScheme { get; set; }
}
var root = JsonConvert.DeserializeObject<RootElement>(json);

就我个人而言,我会把这个该死的东西命名为PriceSchemes(如果你这样做的话,反序列化效果很好),但正如我所提到的,为了兼容,我不能这样做。我们在服务器和客户端上使用相同的数据协定类(来自共享DLL),并使用JSON对其进行序列化。NET。

我的猜测是JSON。NET尝试将List直接反序列化为PriceScheme,因为名称匹配。有没有办法配置/禁用此行为?

示例JSON:

{
    "PriceScheme": [{
        "PriceSchemeId": 1,
        "DisplayText": null,
        "Connector": 0,
        "ExpiryDate": null,
        "Tariff": [{
            "TariffId": 1,
            "DisplayText": {
                "Language": null,
                "Text": "DefaulttesttariffforoffpeakusingkWh."
            },
            "PricingUnit": 2,
            "Currency": {
                "StrCurrency": "EUR"
            },
            "PriceTaxed": 0.12,
            "PriceUntaxed": 0.1,
            "TaxPct": 0.2,
            "Condition": "OffPeak"
        },
        {
            "TariffId": 2,
            "DisplayText": {
                "Language": null,
                "Text": "DefaulttesttariffforoffpeakusingkWh."
            },
            "PricingUnit": 1,
            "Currency": {
                "StrCurrency": "EUR"
            },
            "PriceTaxed": 36.0,
            "PriceUntaxed": 0.0,
            "TaxPct": 0.0,
            "Condition": "OffPeak"
        }],
        "LocalCalculationAllowed": true
    }]
}

根元素类称为SetPricingReq:

public class SetPricingReq
    {
        public SetPricingReq(PriceScheme priceScheme)
        {
            this.PriceScheme = new List<PriceScheme> { priceScheme };
        }
        [Required]
        public List<PriceScheme> PriceScheme { get; set; }
    }

下一个(它已经失败了,所以我跳过剩下的)是PriceScheme:

public class PriceScheme
    {
        public PriceScheme(int priceSchemeId, Tariff tariff, bool localCalculationAllowed)
        {
            this.PriceSchemeId = priceSchemeId;
            this.Tariff = new List<Tariff> { tariff };
            this.LocalCalculationAllowed = localCalculationAllowed;
        }
        [Required]
        public int PriceSchemeId { get; set; }
        public LocalizedText DisplayText { get; set; }
        public ConnectorType Connector { get; set; }
        public DateTime? ExpiryDate { get; set; }
        [Required]
        public List<Tariff> Tariff { get; set; }
        [Required]
        public bool LocalCalculationAllowed { get; set; }
    }

JSON.NET反序列化列表<;TypeX>;名为TypeX的属性

Dynamic有助于此场景

你可能不需要类RootElement,你做为:

dynamic root = JsonConvert.DeserializeObject(json, typeof(object));

您可以使用自定义合约解析器来明确定义如何反序列化某个字段:

public class ConverterContractResolver : DefaultContractResolver
{
    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
        foreach(var property in properties.Where(p => p.PropertyName == "MyProperty"))
            property.Converter = new CustomConverter();
        return properties;
    }
}

public abstract class CustomConverter : JsonConverter
{
    public override bool CanConvert(Type t)
    {
        return typeof(MyType).IsAssignableFrom(t);
    }
    public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
    {
        return new MyType();
    }
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

我们发现,反序列化失败是因为数据类没有实现默认构造函数(我们正在实现的协议要求某些字段不能为null,所以我们确保它们不能为null)。因此,我们要么必须添加公共默认构造函数,要么找到一种方法让自定义转换器解决方案使用它们的非默认构造函数来创建对象。

更新:更确切地说,JSON.net使用了非默认构造函数,但由于该属性的逻辑定义为1…*,我们只向该类的构造函数添加了一个PriceScheme,而不是List。然后,JSON.net将参数名称映射到属性,找到匹配项,然后抱怨类型不兼容,这是正确的,因为它从JSON中获得了一个集合,但无法传入。