c# – 避免将JSON字符串标记反序列化为数字属性

JSON看起来像这样:

{
    "x": "50"
}

这堂课看起来像这样:

public class Test
{
    public float? x { get; set; }
}

并在使用时

var test = JsonConvert.DeserializeObject<Test>(json);

抛出没有异常,JSON.NET只是将字符串值“50”转换为浮点值50.0.

这个问题是在输入验证的背景下提出的.我想得到一个例外,因为JSON字符串不符合合同(x字段应该是一个真正的浮点数).

我不想在’Test’类中使用属​​性注释.

是否有可以用来避免这种情况的JsonSerializerSettings?

最佳答案
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());

转载注明原文:c# – 避免将JSON字符串标记反序列化为数字属性 - 代码日志