c# - 在自定义 JsonConverter 中,如何确定 Utf8JsonReader 数字标记是小数还是长整数?
问题描述
我有这个jsonconverter,它需要将给定的属性值转换为小数或长整数,具体取决于值 - 但我似乎无法确定属性值何时是小数或长整数,因为 tokentype 只能检测数字.. . 我该如何解决这个问题?
public override IDictionary<string, object> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
IDictionary<string, object> output = new Dictionary<string, object>();
while (reader.Read() && reader.TokenType != JsonTokenType.EndObject)
{
string propertyName = reader.GetString();
reader.Read();
object? propertyValue = null;
switch (reader.TokenType)
{
case JsonTokenType.Number:
propertyValue = reader.GetInt64(); // or could be a decimal for where I should reader.GetDecimal()
break;
case JsonTokenType.String:
if (reader.TryGetDateTime(out DateTime value))
{
propertyValue = value;
}
else
{
propertyValue = reader.GetString();
}
break;
case JsonTokenType.True:
case JsonTokenType.False:
propertyValue = reader.GetBoolean();
break;
}
output.Add(propertyName, propertyValue);
}
return output;
}
解决方案
您可以使用Utf8JsonReader.TryGetInt64(out long value)
andUtf8JsonReader.TryGetDecimal(out decimal value)
来测试以查看当前值是否可以成功解析为 along
或 a decimal
。
因此,您修改后的Read()
方法应如下所示:
public override IDictionary<string, object> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
// Assert we are currently at the beginning of an object
if (reader.TokenType != JsonTokenType.StartObject)
throw new JsonException(string.Format("Unexpected token {0}", reader.TokenType));
IDictionary<string, object> output = new Dictionary<string, object>();
while (reader.Read() && reader.TokenType != JsonTokenType.EndObject)
{
string propertyName = reader.GetString()!;
reader.Read();
object? propertyValue;
switch (reader.TokenType)
{
case JsonTokenType.Number:
if (reader.TryGetInt64(out var l))
propertyValue = l;
else if (reader.TryGetDecimal(out var d))
propertyValue = d;
else
{
// Either store the value as a string, or throw an exception.
using var doc = JsonDocument.ParseValue(ref reader);
propertyValue = doc.RootElement.ToString();
throw new JsonException(string.Format("Cannot parse number: {0}", propertyValue));
}
break;
case JsonTokenType.String:
if (reader.TryGetDateTime(out var dt))
propertyValue = dt;
else
propertyValue = reader.GetString();
break;
case JsonTokenType.True:
case JsonTokenType.False:
propertyValue = reader.GetBoolean();
break;
case JsonTokenType.Null:
propertyValue = null;
break;
default:
// An unexpected token type such as an object or array.
// You must either skip it or throw an exception.
reader.Skip();
propertyValue = null;
throw new JsonException(string.Format("Unexpected token {0}", reader.TokenType));
//break;
}
// Since your converter is of type IDictionary<string, object> I assume you don't want to allow null values.
// If you do want to allow null values you should declare it as IDictionary<string, object?>
if (propertyValue == null)
throw new JsonException("null value");
output.Add(propertyName, propertyValue);
}
return output;
}
笔记:
虽然
Utf8JsonReader
会在格式错误的 JSON 上引发异常,但转换器有责任处理任何类型的有效值标记,并在任何不受支持的值类型上引发异常。我修改了转换器以根据需要为意外的值类型抛出异常。
由于您似乎启用了可空引用类型检查
propertyValue
,因此我修改了您的代码以在为空时抛出异常。如果您想允许 null 属性值,您应该将您的转换器声明为JsonConverter<IDictionary<string, object?>>
.您的转换器仅处理原始值。如果您想将其扩展为将嵌套对象反序列化为嵌套
Dictionary<string, object>
值,并将嵌套数组反序列化为嵌套List<object>
值,您可以查看C# - Deserializing nested json to nested Dictionary<string, object>的ObjectAsPrimitiveConverter
这个答案。
演示小提琴在这里。
推荐阅读
- algorithm - 多边形算法中的多边形
- swift - DispatchWorkItem 如何取消递归过程?
- javascript - Javascript 自动触发按钮提交带有动态操作链接的 php 表单
- postgresql - 如何使用自定义类型在 postgres(数组)类型中创建类型
- sql - SQL Server SMO 查询性能(2014 与 2017)
- ios - 使用电话号码在 IOS 上通过 Firebase 进行身份验证
- javascript - 无法使用 jQuery 获取 .attr('aria-controls')
- sql - Django 中的多个数据库 - MSSQL
- bukkit - 持久数据容器未保存到块
- python - Pandas, read_sql() - 从 SQL Server 读取