名为TypeX

时间:2015-06-26 11:34:12

标签: c# json json.net

我们目前正在实现基于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; }
    }

3 个答案:

答案 0 :(得分:0)

动态有助于此方案

你可能不需要类RootElement,你可以这样做:

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

答案 1 :(得分:0)

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

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();
    }
}

答案 2 :(得分:0)

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

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