且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何更改数字反序列化的默认类型?

更新时间:2022-03-23 09:59:30

据我所知,没有内置的方法可以做到这一点.

As far as I know, there is no built-in way to do that.

有一个问题关于这个主题,但它已经关闭.作者对这个问题的一些评论:

There was an issue on this subject, but it has been closed. Some comments from the author on the issue:

Json.NET 默认将整数值读取为 Int64,因为无法知道该值应该是 Int32 还是 Int64,并且 Int64 不太可能溢出.对于类型化的属性,反序列化器知道将 Int64 转换为 Int32,但是因为您的属性是无类型的,所以您得到的是 Int64.[...] 这正是 Json.NET 的工作方式.

Json.NET by default reads integer values as Int64 because there is no way to know whether the value should be Int32 or Int64, and Int64 is less likely to overflow. For a typed property the deserializer knows to convert the Int64 to a Int32 but because your property is untyped you are getting an Int64. [...] It is just the way Json.NET has to work.

最简单的解决方案当然是将类型更改为 Dictionary<string, int>,但我想您不仅在阅读数字,因此会被 object.

The easiest solution would of coure be to change the type to Dictionary<string, int>, but I suppose you are not only reading numerics and thus are stuck with object.

另一种选择是使用 序列化回调 并手动转换那些 Int64Int32 或创建您自己的 Contract Resolver JsonConverter 直接控制(反)序列化.

Another option would be to either use Serialization Callbacks and manually convert those Int64s to Int32 or create your own Contract Resolver JsonConverter and directly control the (de-)serialization.

我创建了一个更具体的小例子.

I created a little example to be more specific.

这是一个非常基本的转换器,仅适用于您的特定字典:

Here is a very basic converter that only works with your specifc Dictionary:

public class Int32Converter : JsonConverter {
    public override bool CanConvert(Type objectType) {
        // may want to be less concrete here
        return objectType == typeof(Dictionary<string, object>);
    }

    public override bool CanWrite {
        // we only want to read (de-serialize)
        get { return false; }
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
        // again, very concrete
        Dictionary<string, object> result = new Dictionary<string, object>();
        reader.Read();

        while (reader.TokenType == JsonToken.PropertyName) {
            string propertyName = reader.Value as string;
            reader.Read();

            object value;
            if (reader.TokenType == JsonToken.Integer)
                value = Convert.ToInt32(reader.Value);      // convert to Int32 instead of Int64
            else
                value = serializer.Deserialize(reader);     // let the serializer handle all other cases
            result.Add(propertyName, value);
            reader.Read();
        }

        return result;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) {
        // since CanWrite returns false, we don't need to implement this
        throw new NotImplementedException();
    }
}

您可以使用属性来装饰您的转换器的成员或将其作为参数传递 到(反)序列化方法.这是我使用属性的示例:

You can either use attributes to decorate members with your converter or pass it as parameter to a (de-)serialize method. Here's an example where I used an attribute:

    [JsonObject]
public class MyObject {
    [JsonConverter(typeof(Int32Converter))]
    public Dictionary<string, object> Properties { get; set; }
}

这是我用来测试实现的代码:

And here's the code I used to test the implementation:

class Program {
    static void Main(string[] args) {
        MyObject test = new MyObject();
        test.Properties = new Dictionary<string, object>() { { "int", 15 }, { "string", "hi" }, { "number", 7 } };
        Print("Original:", test);

        string json = JsonConvert.SerializeObject(test);
        Console.WriteLine("JSON:
{0}
", json);

        MyObject parsed = JsonConvert.DeserializeObject<MyObject>(json);
        Print("Deserialized:", parsed);
    }

    private static void Print(string heading, MyObject obj) {
        Console.WriteLine(heading);
        foreach (var kvp in obj.Properties)
            Console.WriteLine("{0} = {1} of {2}", kvp.Key, kvp.Value, kvp.Value.GetType().Name);
        Console.WriteLine();
    }
}

没有转换器,结果将是:

Without the converter, the result would be:

Deserialized:
int = 15 of Int64
string = hi of String
number = 7 of Int64

使用转换器是:

Deserialized:
int = 15 of Int32
string = hi of String
number = 7 of Int32