如何强制将特定 属性 反序列化为字符串而不是数字?
How to force a particular property to be deserialized as string instead of number?
我有不同的后端返回几乎相同的 JSON 数据模型,除了带有 id
字段的嵌套 json 对象,有时可以是纯数字,例如:
{ "something": { "id": 1 } }
或者一个字符串,比如:
{ "something": { "id": "ex.GUID" } }
此外,该模型由可空值、不同的 System
类型和自定义 class 组成。我希望那些 json 数字 1
始终设置为 "1"
(因此 C# class 模型将此 属性 设置为 public string Id { get; set; }
), 可能是为了那个精确 属性.
有没有JsonConverter<T>
或属性[Attribute]
可以小心处理这样的parsing/deserialization?
ps:当前的JsonConverter<object>
答案似乎不能很好地处理(例外)上述情况
您必须为此使用自定义 JsonConverter<T>
。
/// taken from https://www.thecodebuzz.com/system-text-json-create-a-stringconverter-json-serialization/
public class StringConverter : System.Text.Json.Serialization.JsonConverter<string>
{
public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.Number)
{
var stringValue = reader.GetInt32();
return stringValue.ToString();
}
else if (reader.TokenType == JsonTokenType.String)
{
return reader.GetString();
}
throw new System.Text.Json.JsonException();
}
public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options)
{
writer.WriteStringValue(value);
}
}
并在 JsonSerializerOptions
中注册
var options = new JsonSerializerOptions
{
Converters = { new StringConverter() },
PropertyNameCaseInsensitive = true,
};
var jsonA = "{ \"something\": { \"id\": \"ex.GUID\" } }";
var a = JsonSerializer.Deserialize<RootObject>(jsonA, options);
var jsonB = "{ \"something\": { \"id\": 1 } }";
var b = JsonSerializer.Deserialize<RootObject>(jsonB, options);
完整示例in this fiddle
为了完整起见,您可以用 object
来解决这个问题。
using System.Text.Json;
DeserialiseAndPrint("{ \"something\": { \"id\": 1 } }");
DeserialiseAndPrint("{ \"something\": { \"id\": \"ex.GUID\" } }");
DeserialiseAndPrint("{ \"something\": { } }");
void DeserialiseAndPrint(string v)
{
JsonSerializerOptions options = new (){ PropertyNameCaseInsensitive = true };
var o = JsonSerializer.Deserialize<RootObject>(v, options);
Console.WriteLine($"{o?.Something?.Id} -> {o?.Something?.IdParsed}");
}
class RootObject
{
public Something? Something { get; set; }
}
class Something
{
public object? Id { get; set; }
public string? IdParsed => Id?.ToString();
}
这会打印:
1 -> 1
ex.GUID -> ex.GUID
->
我有不同的后端返回几乎相同的 JSON 数据模型,除了带有 id
字段的嵌套 json 对象,有时可以是纯数字,例如:
{ "something": { "id": 1 } }
或者一个字符串,比如:
{ "something": { "id": "ex.GUID" } }
此外,该模型由可空值、不同的 System
类型和自定义 class 组成。我希望那些 json 数字 1
始终设置为 "1"
(因此 C# class 模型将此 属性 设置为 public string Id { get; set; }
), 可能是为了那个精确 属性.
有没有JsonConverter<T>
或属性[Attribute]
可以小心处理这样的parsing/deserialization?
ps:当前的JsonConverter<object>
答案似乎不能很好地处理(例外)上述情况
您必须为此使用自定义 JsonConverter<T>
。
/// taken from https://www.thecodebuzz.com/system-text-json-create-a-stringconverter-json-serialization/
public class StringConverter : System.Text.Json.Serialization.JsonConverter<string>
{
public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.Number)
{
var stringValue = reader.GetInt32();
return stringValue.ToString();
}
else if (reader.TokenType == JsonTokenType.String)
{
return reader.GetString();
}
throw new System.Text.Json.JsonException();
}
public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options)
{
writer.WriteStringValue(value);
}
}
并在 JsonSerializerOptions
var options = new JsonSerializerOptions
{
Converters = { new StringConverter() },
PropertyNameCaseInsensitive = true,
};
var jsonA = "{ \"something\": { \"id\": \"ex.GUID\" } }";
var a = JsonSerializer.Deserialize<RootObject>(jsonA, options);
var jsonB = "{ \"something\": { \"id\": 1 } }";
var b = JsonSerializer.Deserialize<RootObject>(jsonB, options);
完整示例in this fiddle
为了完整起见,您可以用 object
来解决这个问题。
using System.Text.Json;
DeserialiseAndPrint("{ \"something\": { \"id\": 1 } }");
DeserialiseAndPrint("{ \"something\": { \"id\": \"ex.GUID\" } }");
DeserialiseAndPrint("{ \"something\": { } }");
void DeserialiseAndPrint(string v)
{
JsonSerializerOptions options = new (){ PropertyNameCaseInsensitive = true };
var o = JsonSerializer.Deserialize<RootObject>(v, options);
Console.WriteLine($"{o?.Something?.Id} -> {o?.Something?.IdParsed}");
}
class RootObject
{
public Something? Something { get; set; }
}
class Something
{
public object? Id { get; set; }
public string? IdParsed => Id?.ToString();
}
这会打印:
1 -> 1
ex.GUID -> ex.GUID
->