【问题标题】:C# Convert Json to object with duplicated property name with different data typeC#将Json转换为具有不同数据类型的重复属性名称的对象
【发布时间】:2020-05-12 01:12:03
【问题描述】:

我有一个带有不同数据类型的重复属性名称的 json 字符串。如果我删除了所有重复的其他数据类型,它将正常工作。

{
   "data":[
      {
         "ctr":0,
         "spend":11839.8600,
         "clicks":6402
      },
      {
         "ctr":0,
         "spend":12320.5000,
         "clicks":5789
      },
      {
         "clicks":{
            "value":13156.0,
            "prior_year":0.0,
            "prior_month":14122.0,
            "prior_month_perc":0.0684039087947882736156351792,
            "prior_year_perc":0.0
         }
      }
   ],
   "timing":null,
   "warnings":[

   ],
   "success":true
}

这是我的模型类

  public class MyTestModel
    {
        public int? ctr { get; set; }
        public decimal? spend { get; set; }
        public int? clicks { get; set; }
    }

如果我删除了这个截断的 json 部分,程序将运行。

        {
         "clicks":{
            "value":13156.0,
            "prior_year":0.0,
            "prior_month":14122.0,
            "prior_month_perc":0.0684039087947882736156351792,
            "prior_year_perc":0.0
         }

是否有任何方法可以停止将不支持的类型绑定到模型属性。

【问题讨论】:

  • 您必须使用带有JObject/JToken 类的 Newtonsoft.Json 库来解析它,并用数字替换“坏”节点。但实际上你应该问如何改进你的 JSON,因为那种混合类型不是最佳实践。

标签: c# json


【解决方案1】:

您可以使用JsonConverter 来支持“联合”类中的一种/两种类型。

public partial class ClicksClass
{
    [JsonProperty("value")]
    public long Value { get; set; }

    [JsonProperty("prior_year")]
    public long PriorYear { get; set; }

    [JsonProperty("prior_month")]
    public long PriorMonth { get; set; }

    [JsonProperty("prior_month_perc")]
    public double PriorMonthPerc { get; set; }

    [JsonProperty("prior_year_perc")]
    public long PriorYearPerc { get; set; }
}

public partial struct ClicksUnion
{
    public ClicksClass ClicksClass;
    public long? Integer;

    public static implicit operator ClicksUnion(ClicksClass ClicksClass) => new ClicksUnion { ClicksClass = ClicksClass };
    public static implicit operator ClicksUnion(long Integer) => new ClicksUnion { Integer = Integer };
}

internal static class Converter
{
    public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
    {
        MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
        DateParseHandling = DateParseHandling.None,
        Converters =
        {
            ClicksUnionConverter.Singleton,
            new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }
        },
    };
}

internal class ClicksUnionConverter : JsonConverter
{
    public override bool CanConvert(Type t) => t == typeof(ClicksUnion) || t == typeof(ClicksUnion?);

    public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
    {
        switch (reader.TokenType)
        {
            case JsonToken.Integer:
                var integerValue = serializer.Deserialize<long>(reader);
                return new ClicksUnion { Integer = integerValue };
            case JsonToken.StartObject:
                var objectValue = serializer.Deserialize<ClicksClass>(reader);
                return new ClicksUnion { ClicksClass = objectValue };
        }
        throw new Exception("Cannot unmarshal type ClicksUnion");
    }

    public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
    {
        var value = (ClicksUnion)untypedValue;
        if (value.Integer != null)
        {
            serializer.Serialize(writer, value.Integer.Value);
            return;
        }
        if (value.ClicksClass != null)
        {
            serializer.Serialize(writer, value.ClicksClass);
            return;
        }
        throw new Exception("Cannot marshal type ClicksUnion");
    }

    public static readonly ClicksUnionConverter Singleton = new ClicksUnionConverter();
}

这意味着,一旦解析,每当您到达ClickUnion 实例时,您都可以检查哪个字段不为空,而这就是您使用的字段。当然,这取决于您的用例。

顺便说一句,我使用 this web site 从 json 编写类

【讨论】:

    【解决方案2】:

    我假设您正在使用 JsonConvert.DeserializeObject 反序列化您的 json 字符串。
    这样做时,数据类型不匹配会导致错误,您可以使用JsonSerializerSettings 安全地处理此错误,如下所示

    MyTestModel result = JsonConvert.DeserializeObject<MyTestModel>("{json string}", 
                                                               new JsonSerializerSettings {
                                                                  Error = MethodToHandleError
                                                               });
    

    然后定义MethodToHandleError 如下所示。每当发生反序列化错误时都会调用它:

    public void MethodToHandleError(object sender, ErrorEventArgs args)
    {
        // log error message -> args.ErrorContext.Error.Message
        // you can also write your own logic here
        args.ErrorContext.Handled = true;
    }
    

    【讨论】:

      猜你喜欢
      • 2021-11-21
      • 1970-01-01
      • 1970-01-01
      • 2021-10-24
      • 2020-12-17
      • 2020-02-02
      • 2017-05-23
      • 2021-07-23
      • 1970-01-01
      相关资源
      最近更新 更多