【问题标题】:Can I use a set method instead of a Json Property?我可以使用 set 方法而不是 Json 属性吗?
【发布时间】:2022-01-04 09:51:02
【问题描述】:

我正在使用它来反序列化来自 Api 的 Json 响应。

var apiResponse = await GetAsync<MyResponseModel>(request);

在我的响应模型中,有一个 int 属性,但 api 出于某种原因将其格式化为浮点数。 所以它看起来像这样:

{
"Quantity": 6.000
}

现在我用这个技巧来解析它:

[JsonProperty("Quantity")]
private float QuantityFloat {
    set => Quantity = IsInt(value) ? (int) value: throw new ArgumentException("Tried to parse number to Quantity that is not an int.");
}

public int Quantity { get; set; }

private static bool IsInt(float value)
{
    var x = (int) value;
    var temp2 = value - x;
    return temp2 <= 0;
}

我的 linter 现在抱怨:“只有 setter 的属性令人困惑且违反直觉。相反,如果可能,应该添加属性 getter,或者应该用 setter 方法替换属性。” 所以我问自己是否有更好更优雅的方式来做到这一点。

【问题讨论】:

  • 一些简单的事情(也许不是最好的,但我希望它至少没问题)是向属性QuantityFloat 添加一个getter,将setter 更改为仅采用浮点值(无转换),以删除 Quantity setter 并更改它的 getter 以使 QuantityFloatvalue 转换
  • 如果您知道自己在做什么,您可以指示 linter 忽略该属性。
  • 为什么不能声明类型为十进制?我想我的问题是,这个属性是如何在你的应用程序中使用的,为什么它需要是一个整数?
  • 那么物品的数量只能是整数。 Api 奇怪地给了我一个浮点数,虽然它从来没有小数。

标签: c# json api .net-core serialization


【解决方案1】:

我建议创建一个JsonConverter&lt;int&gt;,它可以同时处理整数和十进制格式的值:

(此解决方案适用于 System.Text.Json)

public class IntConverter : JsonConverter<int>
{
    public override int Read(ref Utf8JsonReader reader, System.Type typeToConvert, JsonSerializerOptions options)
    {
        if (reader.TryGetInt32(out var intVal))
        {
            return intVal;
        }
        // customize this part as necessary to satisfactorily deserialize
        // the float value as int, or throw exception, etc.
        float floatValue = reader.GetSingle();
        return (int)floatValue;
    }

    public override void Write(Utf8JsonWriter writer, int value, JsonSerializerOptions options)
    {
        throw new NotImplementedException();
    }
}

然后您可以使用[JsonConverter(typeof(IntConverter))] 装饰您的属性,这将导致在序列化期间使用转换器:

public class Model
{
    [JsonConverter(typeof(IntConverter))]
    public int Quantity { get; set; }
}

像这样处理它消除了对任何额外属性的需求,从而简化了您的解决方案。如果您必须在多个地方处理这种情况,则尤其如此。

Try it online


JSON.NET 解决方案:

public class IntConverter : JsonConverter<int>
{
    public override int ReadJson(JsonReader reader, Type objectType, int existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Float)
        {
            // customize this part as necessary to satisfactorily deserialize
            // the float value as int, or throw exception, etc.
            double value = (double)reader.Value;
            return (int)value;
        }
        long intVal = (long)reader.Value;
        return (int)intVal;
    }

    public override void WriteJson(JsonWriter writer, int value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

使用以下型号:

public class Model
{
    [JsonConverter(typeof(IntConverter))]
    public int Quantity { get; set; }
}

Try it online

【讨论】:

  • 尝试使用这个我得到一个例外:Deserialization of response content did not succeed! Message: Could not convert string to integer: 6.0000. Newtonsoft.Json.JsonReader.ReadInt32String(String s)我认为它不使用自定义转换器出于某种原因。这是我的代码:[System.Text.Json.Serialization.JsonConverter(typeof(IntConverter))] [Newtonsoft.Json.JsonProperty("Quantity")] public int Quantity { get; set; }
  • 等等...您使用的是 JSON.NET 而不是 System.Text.Json?
  • @lumpigerAffe 我现在添加了 JSON.NET 解决方案。如果您使用 JSON.NET 进行反序列化,请确保使用 JSON.NET 包中的 JsonConverter 基类和 JsonConverterAttribute 属性类型,而不是 System.Text.Json 类型。
  • 是的,我正在使用 JSON.NET。很抱歉没有告诉您,谢谢您的详细回答!
猜你喜欢
  • 1970-01-01
  • 2011-10-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-23
  • 1970-01-01
  • 2017-06-26
相关资源
最近更新 更多