簡體   English   中英

C# Newtonsoft.Json 自定義解串器

[英]C# Newtonsoft.Json Custom Deserializer

我正在使用 API 以不同於我習慣處理的方式返回結果給我,而且看起來不標准。

例如,這里有一段客戶數據:

{
    "CustomerID": {
        "value": "EXAMPLE"
    },
    "CustomerCurrencyID": {
        "value": "USD"
    }
}

該“價值”屬性似乎非常不必要,所以我想看看我是否可以一起繞過它並將 JSON 反序列化為 object ,如下所示:

class Customer {
    public string CustomerID { get; set; }
    public string CustomerCurrencyID { get; set; }
}

我目前正在編寫一個自定義的 JsonConverter 來處理這個問題,所以如果我走在正確的道路上,請告訴我,但這里的任何提示/技巧將不勝感激!

您可以使用通用的自定義JsonConverter來執行此操作,如下所示:

public class WrapWithValueConverter<TValue> : JsonConverter
{
    // Here we take advantage of the fact that a converter applied to a property has highest precedence to avoid an infinite recursion.
    class DTO { [JsonConverter(typeof(NoConverter))] public TValue value { get; set; } public object GetValue() => value; }

    public override bool CanConvert(Type objectType) => typeof(TValue).IsAssignableFrom(objectType);
    
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        => serializer.Serialize(writer, new DTO { value = (TValue)value });

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        => serializer.Deserialize<DTO>(reader)?.GetValue();
}

public class NoConverter : JsonConverter
{
    // NoConverter taken from this answer https://stackoverflow.com/a/39739105/3744182
    // By https://stackoverflow.com/users/3744182/dbc
    // To https://stackoverflow.com/questions/39738714/selectively-use-default-json-converter
    public override bool CanConvert(Type objectType)  { throw new NotImplementedException(); /* This converter should only be applied via attributes */ }
    public override bool CanRead => false;
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) => throw new NotImplementedException();
    public override bool CanWrite => false;
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) => throw new NotImplementedException();
}

然后你可以將它應用到你的 model 如下:

class Customer {
    [JsonConverter(typeof(WrapWithValueConverter<string>))]
    public string CustomerID { get; set; }
    [JsonConverter(typeof(WrapWithValueConverter<string>))]
    public string CustomerCurrencyID { get; set; }
}

演示小提琴#1在這里

或者,如果您希望將所有字符串包裝在{"value": <string value>} object 中,則可以在序列化和反序列化時將轉換器添加到JsonSerializerSettings.Converters

var settings = new JsonSerializerSettings
{
    Converters = { new WrapWithValueConverter<string>() },
};

var model = JsonConvert.DeserializeObject<Customer>(json, settings);

var json2 = JsonConvert.SerializeObject(model, Formatting.Indented, settings);

演示小提琴#2在這里

如果您的值是一個enum並且您想將其序列化為字符串,您可以使用以下命令將NoConverter替換為StringEnumConverter

public class WrapEnumWithValueConverter<TEnum> : JsonConverter where TEnum: Enum
{
    // Here we take advantage of the fact that a converter applied to a property has highest precedence to avoid an infinite recursion.
    class DTO { [JsonConverter(typeof(StringEnumConverter))] public TEnum value { get; set; } public object GetValue() => value; }

    public override bool CanConvert(Type objectType) => typeof(TEnum).IsAssignableFrom(objectType);

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        => serializer.Serialize(writer, new DTO { value = (TEnum)value });

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        => serializer.Deserialize<DTO>(reader)?.GetValue();
}

演示小提琴#3在這里

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM