问题描述
我正在将一些属性反序列化为 Dictionary<string, object>
.
I'm deserializing some properties to a Dictionary<string, object>
.
当我反序列化一些 json 时,它会使用 Int64
对象而不是 Int32
填充 Dictionary
.我希望它选择 Int32
作为默认值,因为我知道我可以拥有在转换时会溢出的 javascript Numerics.在这种情况下抛出异常是完全可以接受的.
When I deserialize some json, it populates the Dictionary
with Int64
objects rather than Int32
. I would like it to choose Int32
as the default well knowing that I could have javascript Numerics that would overflow on conversion. Throwing an exception in that case would be entirely acceptable.
有什么方法可以实现吗?我希望有一些不错的属性或方便的接口可以实现并添加到 JsonSerializer
.而且我担心我必须深入到 Json.NET 的深处.
Is there any way to achieve that? I'm hoping for some nice attributes or a convenient interface that could be implemented and added to the JsonSerializer
. And I fear that I have to go deep down into the depths of Json.NET.
基本上我想有一些方法来控制对象的已知类型,以便我可以获得 Int32
的而不是 Int64
和 DateTimes
而不是 Strings
.
Basically I would like to have some way to control the known types for the objects so that I could get Int32
's instead of Int64
and DateTimes
instead of Strings
.
推荐答案
据我所知,没有内置的方法可以做到这一点.
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
.
另一种选择是使用 序列化回调 并手动转换那些 Int64
到 Int32
或创建您自己的 Contract Resolver JsonConverter 直接控制(反)序列化.
Another option would be to either use Serialization Callbacks and manually convert those Int64
s 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
这篇关于如何更改数字反序列化的默认类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!