使用.Net Core 3的新System.Text.Json JsonSerializer,如何自动转换类型(例如,将int转换为字符串并将string转换为int)?例如,这会引发异常,因为JSON中的id
是数字,而C#的Product.Id
需要一个字符串:
public class HomeController : Controller
{
public IActionResult Index()
{
var json = @"{""id"":1,""name"":""Foo""}";
var o = JsonSerializer.Deserialize<Product>(json, new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true,
});
return View();
}
}
public class Product
{
public string Id { get; set; }
public string Name { get; set; }
}
Newtonsoft的Json.Net处理得很好。如果在C#期望一个字符串的情况下传递数字值(反之亦然),则没关系,一切都按预期进行了反序列化。如果您无法控制作为JSON传递的类型格式,如何使用System.Text.Json来处理呢?
答案 0 :(得分:1)
您可以在模型类中使用 JsonNumberHandlingAttribute 来指定如何处理数字反序列化。允许的选项在 JsonNumberHandling 枚举中指定。
用法示例:
public class Product
{
[JsonNumberHandling(JsonNumberHandling.WriteAsString)]
public string Id { get; set; }
public string Name { get; set; }
}
如果需要从string
到int
的序列化,可以使用JsonNumberHandling.AllowReadingFromString
答案 1 :(得分:1)
在选项中,将 NumberHandling 属性设置为 group color freq
0 A red 0.4
1 A red 0.4
2 A green 0.4
3 A blue 0.2
4 A green 0.4
5 B red 0.75
6 B red 0.75
7 B red 0.75
8 B green 0.25
9 C blue 0.33
10 C green 0.33
11 C red 0.33
:
AllowReadingFromString
答案 2 :(得分:0)
不用担心。只需在类中添加一个属性,该属性将以所需的类型返回所需的项目。
public class Product
{
public int Id { get; set; }
public string IdString
{
get
{
return Id.ToString();
}
}
public string Name { get; set; }
}
答案 3 :(得分:0)
新的System.Text.Json
API公开了一个JsonConverter
API,使我们可以根据需要转换类型。
例如,我们可以创建一个从number
到string
的通用转换器:
public class AutoNumberToStringConverter : JsonConverter<object>
{
public override bool CanConvert(Type typeToConvert)
{
return typeof(string) == typeToConvert;
}
public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if(reader.TokenType == JsonTokenType.Number) {
return reader.TryGetInt64(out long l) ?
l.ToString():
reader.GetDouble().ToString();
}
if(reader.TokenType == JsonTokenType.String) {
return reader.GetString();
}
using(JsonDocument document = JsonDocument.ParseValue(ref reader)){
return document.RootElement.Clone().ToString();
}
}
public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options)
{
writer.WriteStringValue( value.ToString());
}
}
使用MVC / Razor Page时,我们可以在启动时注册此转换器:
services.AddControllersWithViews().AddJsonOptions(opts => {
opts.JsonSerializerOptions.PropertyNameCaseInsensitive= true;
opts.JsonSerializerOptions.Converters.Insert(0, new AutoNumberToStringConverter());
});
,然后MVC / Razor将自动处理类型转换。
或者如果您想手动控制序列化/反序列化:
var opts = new JsonSerializerOptions {
PropertyNameCaseInsensitive = true,
};
opts.Converters.Add(new AutoNumberToStringConverter());
var o = JsonSerializer.Deserialize<Product>(json,opts) ;
您可以通过类似的方式启用字符串到数字类型的转换,如下所示:
public class AutoStringToNumberConverter : JsonConverter<object>
{
public override bool CanConvert(Type typeToConvert)
{
// see https://stackoverflow.com/questions/1749966/c-sharp-how-to-determine-whether-a-type-is-a-number
switch (Type.GetTypeCode(typeToConvert))
{
case TypeCode.Byte:
case TypeCode.SByte:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
case TypeCode.Decimal:
case TypeCode.Double:
case TypeCode.Single:
return true;
default:
return false;
}
}
public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if(reader.TokenType == JsonTokenType.String) {
var s = reader.GetString() ;
return int.TryParse(s,out var i) ?
i :
(double.TryParse(s, out var d) ?
d :
throw new Exception($"unable to parse {s} to number")
);
}
if(reader.TokenType == JsonTokenType.Number) {
return reader.TryGetInt64(out long l) ?
l:
reader.GetDouble();
}
using(JsonDocument document = JsonDocument.ParseValue(ref reader)){
throw new Exception($"unable to parse {document.RootElement.ToString()} to number");
}
}
public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options)
{
var str = value.ToString(); // I don't want to write int/decimal/double/... for each case, so I just convert it to string . You might want to replace it with strong type version.
if(int.TryParse(str, out var i)){
writer.WriteNumberValue(i);
}
else if(double.TryParse(str, out var d)){
writer.WriteNumberValue(d);
}
else{
throw new Exception($"unable to parse {str} to number");
}
}
}
答案 4 :(得分:0)
对我来说不幸的是,itminus的示例不起作用,这是我的变体。
/*
* setPrice test
*/
@Test
public void testSetPrice_1() throws RecipeException {
r1.setPrice("25");
r1.setPrice("0");
}
/*
* setPrice test
*/
@Test(expected = RecipeException.class)
public void testSetPrice_2() throws RecipeException {
r1.setPrice("adsada");
r1.setPrice(" ");
r1.setPrice("-1");
}