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

本文关键字:默认 类型 反序列化 何更改 数字 | 更新日期: 2023-09-27 18:16:12

我将一些属性反序列化到Dictionary<string, object>

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

有什么方法可以做到这一点吗?我希望有一些不错的属性或一个方便的接口,可以实现并添加到JsonSerializer。我担心我必须深入到Json.NET的深处。

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

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

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

关于这个主题有一个问题,但是已经解决了。以下是作者对这个问题的一些评论:

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

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

另一个选择是使用序列化回调并手动将这些Int64转换为Int32,或者创建您自己的

契约解析器 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();
    }
}

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

    [JsonObject]
public class MyObject {
    [JsonConverter(typeof(Int32Converter))]
    public Dictionary<string, object> Properties { get; set; }
}
下面是我用来测试实现的代码:
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();
    }
}
如果没有转换器,结果将是:
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

Try

   var variable = Convert.ToInt32(object) 

迭代Dictionary<string,object>一次,用这个Int32重写它的object,或者每次读取object时进行Int32转换。

这对我来说很好:

public class ParseNumbersAsInt32Converter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(long) || objectType == typeof(long?) || objectType == typeof(object);
    }
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        serializer.Serialize(writer, value);
    }
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.Value != null && reader.Value is long)
        {
            return Convert.ToInt32(reader.Value);
        }
        return reader.Value;
    }
}

我接受Enzi的答案,因为这是我想要的。

然而,从那以后我改变了我的策略。

现在我反序列化到一个ChangeSet<T>,而不是字典,它有一个强类型的Entity (T)对象。它还有一个List<string>,其中包含传入json中存在的属性的属性名称。然后在反序列化期间使用自定义MediaFormatter填充该列表。这样我就得到了一个强类型对象,并正确地反序列化了所有的属性,并且我从列表中知道当我想要进行批处理操作时,我应该在我的集合T上设置哪些属性。

这样,我基本上使用我的实体作为DTO,而不必为不同的批处理操作拥有无数不同的DTO。要我说的话,还挺时髦的。:)

我发现了这个问题,因为我遇到了同样的问题。我决定回去把它们转换一下。

var items = GetDataFile<Item[]>("Items");
foreach(var m in items)
{
    // Deserialized int becomes long if object type. I want int.
    foreach(var pk in m.Properties.Keys)
    {
        if(m.Properties[pk] is long)
        {
            m.Properties[pk] = Convert.ToInt32(m.Properties[pk]);
        }
    }
}