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

Mit*_*hon 19 c# json.net

我正在将一些属性反序列化为a Dictionary<string, object>.

当我反序列化JSON一些,它填充DictionaryInt64对象,而不是Int32.我希望它能够选择Int32作为默认值,知道我可以使用转换时会溢出的javascript数字.在这种情况下抛出异常是完全可以接受的.

有没有办法实现这一目标?我希望有一些很好的属性或一个方便的界面,可以实现并添加到JsonSerializer.而且我担心我必须深入到Json.NET的深处.

基本上我想有一些方法来控制对象的已知类型,这样我就可以Int32代替Int64DateTimes不是代替Strings.

enz*_*nzi 22

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

这个问题存在问题,但已经关闭.作者对此问题的一些评论:

默认情况下,Json.NET将整数值作为Int64读取,因为无法知道该值是Int32还是Int64,而Int64不太可能溢出.对于类型化属性,反序列化器知道将Int64转换为Int32,但由于您的属性是无类型的,因此您将获得Int64.[...]这就是Json.NET必须工作的方式.

最简单的解决方案是改变类型Dictionary<string, int>,但我想你不仅仅是阅读数字,因而坚持下去object.

另一个选择是使用序列化回调并手动将它们转换Int64Int32或创建自己的合同解决方案 JsonConverter并直接控制(反)序列化.


编辑: 我创建了一个更具体的例子.

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

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

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:\n{0}\n", 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();
    }
}
Run Code Online (Sandbox Code Playgroud)

没有转换器,结果将是:

Deserialized:
int = 15 of Int64
string = hi of String
number = 7 of Int64
Run Code Online (Sandbox Code Playgroud)

并使用转换器:

Deserialized:
int = 15 of Int32
string = hi of String
number = 7 of Int32
Run Code Online (Sandbox Code Playgroud)