JSON看起来像这样:
{
"x": "50"
}
班级看起来像这样:
public class Test
{
public float? x { get; set; }
}
使用时
var test = JsonConvert.DeserializeObject<Test>(json);
没有抛出异常,JSON.NET只转换字符串值&#34; 50&#34;浮动值为50.0。
这个问题是在输入验证的背景下提出的。我想得到一个例外,因为JSON字符串不符合合同(x
字段应该是一个真正的浮点数。)
而且我不想在“测试”中使用属性注释。类。
是否有可以用来避免这种情况的JsonSerializerSettings?
答案 0 :(得分:5)
JSON.NET自由地将数字字符串("50"
)解析为数字。据我所知,没有任何简单的方法可以解决这个问题。
你可以创建一个不允许这样做的自定义转换器:
public class NumberConverter : JsonConverter
{
private readonly Type[] _typesNotToReadAsString = { typeof(float), typeof(float?) };
public override bool CanConvert(Type objectType)
{
return _typesNotToReadAsString.Any(t => t.IsAssignableFrom(objectType));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JToken token = JToken.Load(reader);
if (_typesNotToReadAsString.Contains(objectType) && token.Type == JTokenType.String)
{
string exceptionString = string.Format("Won't convert string to type {0}", objectType.FullName);
throw new JsonSerializationException(exceptionString);
}
return token.ToObject(objectType);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override bool CanWrite
{
get { return false; }
}
}
转换器报告能够反序列化为指定的类型,在本例中为float
和float?
,但可配置。
反序列化后,它会检查令牌类型。给定JSON输入的一些标记类型:
"50"
:JTokenType.String
50
:JTokenType.Integer
42.1415
:JTokenType.Float
这样,转换器可以确定当前令牌是否按照需要进行格式化。当令牌类型是一个字符串时,上面的转换器将抛出一个异常,表明它不会将字符串转换为所需的类型。
当令牌类型为其他任何内容时,转换器会通过token.ToObject(objectType)
将令牌转换为适当的数字类型。该方法还将通过抛出相应的异常来处理非数字输入,例如“无法将数组转换为单个。”。
鉴于课程Foo
:
public class Foo
{
public float Bar { get; set; }
public string Baz { get; set; }
public float? Qux { get; set; }
}
使用上面的转换器反序列化JSON字符串,这将起作用:
var jsonString = "{ \"Bar\" : 50, \"Baz\" : \"zaB\", \"Qux\" : 42.1415 }";
var foo = JsonConvert.DeserializeObject<Foo>(jsonString, new NumberConverter());
虽然这会抛出:
var jsonString = "{ \"Bar\" : 50, \"Baz\" : \"zaB\", \"Qux\" : \"42.1415\" }";
var foo2 = JsonConvert.DeserializeObject<Foo>(jsonString, new NumberConverter());