将 false 反序列化为 null (System.Text.Json)
Posted
技术标签:
【中文标题】将 false 反序列化为 null (System.Text.Json)【英文标题】:Deserialize false as null (System.Text.Json) 【发布时间】:2020-06-23 08:11:39 【问题描述】:我正在使用一个 API,由于某种原因,它在应该使用 null 的地方使用了 false。我不知道如何正确反序列化它。我试图创建一个自定义 JsonConverter 来解决这个问题,但无法这样做。我想避免使用动态类型。我应该如何反序列化这个?
这是默认响应。
"products": [
"id": 123456789,
"supplier":
"id": 123456,
"title": "abc"
]
我正在反序列化如下。
public class Container
public Product[] products get; set;
public class Product
public ulong id get; set;
public Supplier supplier get; set;
public class Supplier
public ulong id get; set;
public string title get; set;
JsonSerializer.Deserialize<Container>(json)
这是当产品没有供应商时的响应。
"products": [
"id": 123456789,
"supplier": false
]
【问题讨论】:
为了做到这一点,这里的问题是API端点返回false,什么时候应该返回null,或者你不能反序列化序列化的对象? @vasilisdmr 问题是我无法反序列化序列化的对象。很遗憾,我无法更改 API 的行为。 查看以下来自 Microsoft 文档的文章,其中说“不支持反序列化到没有无参数构造函数的引用类型”docs.microsoft.com/en-us/dotnet/standard/serialization/… @Pete,你能用我下面的建议解决你的问题吗?***.com/a/60642484/12509023 【参考方案1】:您可以为supplier
属性创建自定义JsonConverter
:
public class Product
public ulong id get; set;
[JsonConverter(typeof(SupplierConverter))]
public Supplier supplier get; set;
public class SupplierConverter : JsonConverter
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
throw new NotImplementedException();
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
if (reader.TokenType == JsonToken.Boolean)
if ((bool)reader.Value == false)
return null;
return serializer.Deserialize(reader, objectType);
public override bool CanConvert(Type objectType)
return false;
更新:
如果你使用System.Text.Json
,可以试试下面的自定义转换器:
public class SupplierConverter : JsonConverter<Supplier>
public override Supplier Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
if (reader.TokenType == JsonTokenType.False)
return null;
if (options.GetConverter(typeof(JsonElement)) is JsonConverter<JsonElement> converter)
var json = converter.Read(ref reader, typeToConvert, options).GetRawText();
return JsonSerializer.Deserialize<Supplier>(json);
throw new JsonException();
public override void Write(Utf8JsonWriter writer, Supplier value, JsonSerializerOptions options)
throw new NotImplementedException();
【讨论】:
这似乎适用于 Json.NET。我正在使用 System.Text.Json @tzrm,您的示例转换器将按照其编写方式进行堆栈溢出,并且正在做一些不必要的工作 (dotnetfiddle.net/1yqrZ5)。您应该通过选项注册转换器,然后不要在转换器中传递选项,或者在转换器中完全处理供应商转换。以下是您应该考虑编写和使用它的两种方式:dotnetfiddle.net/XFbXB1【参考方案2】:使用System.Text.Json
时,您可以为Supplier
属性实现并注册自己的JsonConverter<T>
。
您可以考虑通过两种方式实现转换器,具体取决于您的需要(是否需要在多个位置使用 Supplier
对象,或者是否需要使用不同的 JsonSerializerOption
设置)。
-
创建一个
JsonConverter<Supplier>
并添加自定义逻辑来处理false
。其余的留给Deserialize
电话。在您的实现中,不要传入选项。然后,在选项中注册此转换器。这是最简单的方法。
// Don't register this converter using an attribute on the Supplier class
// since you are calling Deserialize on this type directly within the converter.
public class SupplierConverter : JsonConverter<Supplier>
public override Supplier Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options)
if (reader.TokenType == JsonTokenType.False)
return null;
// Skip passing options here to avoid ***
// This approach won't work if you have other options that need to be honored
// when deserializing Supplier.
return JsonSerializer.Deserialize<Supplier>(ref reader);
public override void Write(
Utf8JsonWriter writer,
Supplier value,
JsonSerializerOptions options)
throw new NotImplementedException();
// Register the converter within options as follows
// and pass the options the JsonSerializer.Deserialize call.
var options = new JsonSerializerOptions
Converters = new SupplierConverter()
;
-
或者,创建
JsonConverter<Supplier>
并添加自定义逻辑以处理“false”以及Supplier
对象的反序列化。在这种情况下,您可以在选项中注册此转换器,或将其用作Supplier
类本身的属性。如果出于某种原因(例如属性名称的不区分大小写匹配)需要使用自定义选项设置来反序列化供应商,请遵循此方法。
public class SupplierConverter : JsonConverter<Supplier>
public override Supplier Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options)
// Put whatever special case condition here.
// I added a null token check as well, just in case.
if (reader.TokenType == JsonTokenType.False
|| reader.TokenType == JsonTokenType.Null)
return null;
var output = new Supplier();
// Potentially add other error handling for invalid JSON, if needed.
while (reader.Read() && reader.TokenType != JsonTokenType.EndObject)
if (reader.TokenType == JsonTokenType.PropertyName)
if (reader.ValueTextEquals("id"))
if (!reader.Read()) throw new JsonException();
output.id = reader.GetUInt64();
else if (reader.ValueTextEquals("title"))
if (!reader.Read()) throw new JsonException();
output.title = reader.GetString();
if (reader.TokenType != JsonTokenType.EndObject)
throw new JsonException();
return output;
public override void Write(
Utf8JsonWriter writer,
Supplier value,
JsonSerializerOptions options)
throw new NotImplementedException();
// Register the converter within options as follows
// and pass the options the JsonSerializer.Deserialize call.
var options = new JsonSerializerOptions
Converters = new SupplierConverter()
;
// OR
// Use annotate your Supplier class with
// a JsonConverterAttribute.
此文档对您编写自定义转换器很有用:
https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-converters-how-to
以下是相关的 API 文档:
https://docs.microsoft.com/en-us/dotnet/api/system.text.json.serialization.jsonconverter-1?view=netcore-3.1 https://docs.microsoft.com/en-us/dotnet/api/system.text.json.serialization.jsonconverterattribute?view=netcore-3.1这是一个工作示例(当 json 包含 false
供应商时,以及当它在负载中包含实际的 supplier
JSON 对象时):
https://dotnetfiddle.net/XFbXB1
【讨论】:
【参考方案3】:假设你使用的是 Json.Net
var settings = new JsonSerializerSettings();
settings.NullValueHandling = NullValueHandling.Include;
settings.DefaultValueHandling = DefaultValueHandling.Include;
JsonSerializer.Deserialize<Container>(json,settings)
或者试试
var serializeOptions = new JsonSerializerOptions
IgnoreNullValues =false
;
JsonSerializer.Deserialize<Container>(json,serializeOptions)
【讨论】:
以上是关于将 false 反序列化为 null (System.Text.Json)的主要内容,如果未能解决你的问题,请参考以下文章