我正在尝试将此 Newtonsoft.Json.JsonConverter 转换为 System.Text.Json。但是,我只能使用单个基本类型,例如 double,即使在那里我也无法将转换器应用于可空(double?)。如何将其转换为支持可为空和所有数字格式(浮点型、双精度型)。
Newtonsoft.Json
public class DecimalRoundingJsonConverter : JsonConverter
{
private readonly int _numberOfDecimals;
public DecimalRoundingJsonConverter() : this(6)
{
}
public DecimalRoundingJsonConverter(int numberOfDecimals)
{
_numberOfDecimals = numberOfDecimals;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
double input = 0;
if (value is decimal)
{
var d = (decimal)value;
input = Convert.ToDouble(d);
}
else if (value is float)
{
var d = (float)value;
input = Convert.ToDouble(d);
}
else
{
input = (double)value;
}
var rounded = Math.Round(input, _numberOfDecimals);
writer.WriteValue((decimal)rounded);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override bool CanRead
{
get { return false; }
}
public override bool CanConvert(Type objectType)
{
return objectType == typeof(decimal);
}
}
System.Text.Json(基本)
public class DecimalRoundingJsonConverter : JsonConverter<double>
{
private readonly int _numberOfDecimals = 6;
public override double Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options)
{
throw new NotImplementedException();
}
public override void Write(
Utf8JsonWriter writer,
double dvalue,
JsonSerializerOptions options)
{
double input = (double)dvalue;
var rounded = Math.Round(input, _numberOfDecimals);
writer.WriteStringValue(rounded.ToString());
}
}
您可以创建一个适用于所有float
, double
and decimal
值,以及相同的可空值,通过创建JsonConverter<object>
并压倒一切JsonConverter<object>.CanConvert(Type) https://learn.microsoft.com/en-us/dotnet/api/system.text.json.serialization.jsonconverter-1.canconvert?view=net-6.0仅对六种相关类型返回 true。
以下内容完成了这项工作:
public class RoundingJsonConverter : RoundingJsonConverterBase
{
// The converter works for float, double & decimal. Max number of decimals for double is 15, for decimal is 28, so throw an exception of numberOfDecimals > 28.
public RoundingJsonConverter(int numberOfDecimals) => NumberOfDecimals = (numberOfDecimals < 0 || numberOfDecimals > 28 ? throw new ArgumentOutOfRangeException(nameof(numberOfDecimals)) : numberOfDecimals);
protected override int NumberOfDecimals { get; }
}
public class RoundingTo2DigitsJsonConverter : RoundingJsonConverterBase
{
protected override int NumberOfDecimals { get; } = 2;
}
public class RoundingTo6DigitsJsonConverter : RoundingJsonConverterBase
{
protected override int NumberOfDecimals { get; } = 6;
}
public abstract class RoundingJsonConverterBase : JsonConverter<object>
{
protected abstract int NumberOfDecimals { get; }
public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
typeToConvert = Nullable.GetUnderlyingType(typeToConvert) ?? typeToConvert;
if (typeToConvert == typeof(decimal))
return reader.GetDecimal();
else if (typeToConvert == typeof(double))
return reader.GetDouble();
else if (typeToConvert == typeof(float))
return (float)reader.GetDouble();
throw new NotImplementedException();
}
public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options)
{
switch (value)
{
case double d:
writer.WriteNumberValue(Math.Round(d, Math.Min(15, NumberOfDecimals)));
break;
case decimal d:
writer.WriteNumberValue(Math.Round(d, NumberOfDecimals));
break;
case float f:
writer.WriteNumberValue((decimal)Math.Round((decimal)f, NumberOfDecimals));
break;
default:
throw new NotImplementedException();
}
}
public override bool CanConvert(Type typeToConvert)
{
typeToConvert = Nullable.GetUnderlyingType(typeToConvert) ?? typeToConvert;
return typeToConvert == typeof(double) || typeToConvert == typeof(decimal) || typeToConvert == typeof(float);
}
}
Notes:
-
System.Text.Json 没有与 Newtonsoft 等效的系统JsonConverter.CanRead
所以你必须实施Read()
也Write()
.
-
添加转换器时JsonSerializerOptions.Converters
use DecimalRoundingJsonConverter
并将所需的位数作为构造函数参数传递,例如:
var options = new JsonSerializerOptions
{
Converters = { new RoundingJsonConverter(6) },
};
但是,如果您通过属性应用转换器,Microsoft 不允许传递转换器参数(请参阅here https://github.com/dotnet/runtime/issues/54187#issuecomment-869598871以供确认),因此您需要为每个所需的位数创建特定的转换器类型,例如
public class RoundingTo2DigitsJsonConverter : RoundingJsonConverterBase
{
protected override int NumberOfDecimals { get; } = 2;
}
public class RoundingTo6DigitsJsonConverter : RoundingJsonConverterBase
{
protected override int NumberOfDecimals { get; } = 6;
}
然后应用例如如下:
[JsonConverter(typeof(RoundingTo6DigitsJsonConverter))]
public decimal? SixDecimalPlaceValue { get; set; }
-
Nullable.GetUnderlyingType(Type) https://learn.microsoft.com/en-us/dotnet/api/system.nullable.getunderlyingtype可用于获取可空类型的基础类型,例如decimal?
or double?
.
-
JsonConverter<T>.Write()
从未被要求null
可空值除非JsonConverter<T>.HandleNull https://learn.microsoft.com/en-us/dotnet/api/system.text.json.serialization.jsonconverter-1.handlenull被覆盖返回true
.
演示小提琴here https://dotnetfiddle.net/XnOPWk.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)