簡體   English   中英

System.Text.Json 自定義 null 值

[英]System.Text.Json custom null values

我正在使用 api 端點,它們在某些字段中返回無效響應,而不是小數的 null 值。 這是一個例子

{
  "name": "MyName",
  "decimalOne": "0.01",
  "decimalTwo": "None",
  "decimalThree": "-"
}

我希望我的代碼能夠處理他們發送給我的這些自定義“null”事物,就像普通的 null 一樣。 我有辦法做到這一點嗎?

你可以嘗試這樣的事情,(我不知道你有多少個不同的十進制字段)

Name name=System.Text.Json.JsonSerializer.Deserialize<Name>(json);

public class Name
{
    public string name {get; set;}
    
    [JsonPropertyName("decimalOne")]
    public string decimalOneString  { get; set;}
    
    [System.Text.Json.Serialization.JsonIgnore]
    public decimal? decimalOne
    {
        get { if (decimal.TryParse(decimalOneString, out var result)) return result;
        return null;
        }
        set { decimalOneString = value.ToString();}
    }
}

我決定使用我們可以傳入的其他“null”參數來做一個 NullableConverterFactory。

看起來像這樣。

/// <summary>
/// Converter that can parse nullable types. int? decimal? etc
/// </summary>
public class NullableConverterFactory : JsonConverterFactory
{
    private static readonly byte [] EMPTY = Array.Empty<byte>();

    private static readonly HashSet<byte[]> NULL_VALUES = new()
                                                          {
                                                              EMPTY
                                                          };

    /// <summary>
    /// empty constructor.
    /// </summary>
    public NullableConverterFactory()
    {
    }

    /// <summary>
    /// Supply additional accepted null values as byte[] here.
    /// </summary>
    /// <param name="additionalNullValues"></param>
    public NullableConverterFactory(HashSet<byte[]> additionalNullValues)
    {
        foreach (byte[] nullValue in additionalNullValues)
        {
            NULL_VALUES.Add(nullValue);
        }
    }

    /// <summary>
    /// Returns true if this converter can convert the value.
    /// </summary>
    /// <param name="typeToConvert"></param>
    /// <returns></returns>
    public override bool CanConvert(Type typeToConvert) => Nullable.GetUnderlyingType(typeToConvert) != null;

    public override JsonConverter CreateConverter(Type type, JsonSerializerOptions options) => 
        (JsonConverter)Activator.CreateInstance(
                                                typeof(NullableConverter<>).MakeGenericType(
                                                                                            new Type[] { Nullable.GetUnderlyingType(type) }),
                                                BindingFlags.Instance | BindingFlags.Public,
                                                binder: null,
                                                args: new object[] { options, NULL_VALUES },
                                                culture: null);

    class NullableConverter<T> : JsonConverter<T?> where T : struct
    {
        private readonly HashSet<byte[]> _nullValues;

        // DO NOT CACHE the return of (JsonConverter<T>)options.GetConverter(typeof(T)) as DoubleConverter.Read() and DoubleConverter.Write()
        // DO NOT WORK for nondefault values of JsonSerializerOptions.NumberHandling which was introduced in .NET 5
        public NullableConverter(JsonSerializerOptions options, HashSet<byte[]> nullValues)
        {
            _nullValues = nullValues;
        }

        public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            if (reader.TokenType != JsonTokenType.String)
            {
                return JsonSerializer.Deserialize<T>(ref reader, options);
            }

            foreach (byte[] nullValue in _nullValues)
            {
                if (reader.ValueTextEquals(nullValue))
                {
                    return null;
                }
            }

            return JsonSerializer.Deserialize<T>(ref reader, options);
        }           

        public override void Write(Utf8JsonWriter writer, T? value, JsonSerializerOptions options) =>
            JsonSerializer.Serialize(writer, value.Value, options);
    }
}

用法:

new JsonSerializerOptions()
          {
              PropertyNameCaseInsensitive = true,
              Converters =
              {
                  new NullableConverterFactory(new HashSet<byte[]>
                                               {
                                                   Encoding.UTF8.GetBytes("-"),
                                                   Encoding.UTF8.GetBytes("None")
                                               })
              },
              NumberHandling      = JsonNumberHandling.AllowReadingFromString,
              AllowTrailingCommas = true
          };

暫無
暫無

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

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