Json.net DeserializeAnonymousType returns BigInteger 而不是 UInt64
Json.net DeserializeAnonymousType returns BigInteger instead of UInt64
假设我们有以下代码:
Type t = typeof(UInt64);
var def = Activator.CreateInstance(t);
Console.WriteLine(def.GetType());
string json = "18446744073709551615";
object parsedObject = JsonConvert.DeserializeAnonymousType(json, def);
Console.WriteLine(parsedObject.GetType());
输出为:
System.UInt64
System.Numerics.BigInteger
因为我明确地用 def
喂养 DeserializeAnonymousType
,其类型是 UInt64
,我希望 UInt64
也作为输出,特别是因为 18446744073709551615 是有效的UInt64
值(最大值,当然,但我也检查了 18446744073709551614,它是一样的)。
为什么会这样?我检查了 Newtonsoft Github issues,但什么也没发现(至少,未解决的 issues)。
如何强制我预先知道的正确类型(动态地,我只有 System.Type
)?显然,如果它只发生在 UInt64
时,我可以进行检查并显式转换。
您的问题是 JsonConvert.DeserializeAnonymousType<T>(string value, T anonymousTypeObject)
没有达到您的预期。它不会将 JSON 字符串反序列化为 T anonymousTypeObject
参数的 实际类型 。它将 JSON 字符串反序列化为参数的 声明类型 —— 在您的例子中,是 object
.
从reference source可以看出:
public static T DeserializeAnonymousType<T>(string value, T anonymousTypeObject)
{
return DeserializeObject<T>(value);
}
T anonymousTypeObject
从未实际使用过。相反,目标类型完全是在调用 DeserializeAnonymousType
时通过类型推断指定的——特别是根据代码中变量 def
的声明类型。但是 def
被隐式声明为 object
,因为那是 Activator.CreateInstance(Type type)
被声明为 return 的内容。因此 object
是 Json.NET 将 JSON 反序列化为——某种足以捕获传入 JSON 的 .Net 类型。由于 BigInteger
足以捕获传入的 JSON,Newtonsoft 恰好选择了该类型而不是 Uint64
。
如果你想强制Json.NET反序列化为特定对象的实际具体类型,请使用JsonConvert.DeserializeObject(string value,Type type)
:
object parsedObject = JsonConvert.DeserializeObject(json, def.GetType());
演示 fiddle here.
我使用了这个例子并认为我会把它推进到 classes:
的列表
List<_class> listOfClasses = new List<_class>();
var content = response.Content.ReadAsStringAsync().Result;
object parsedObject = JsonConvert.DeserializeAnonymousType(content, Activator.CreateInstance(typeof(_class)));
var _listOfClasses = JsonConvert.DeserializeObject<List<_class>>(parsedObject.ToString());
listOfClasses = _listOfClasses;
这样做是从 API 中使用 TEntity 的列表,然后将其解析回与消费者
匹配的 class
假设我们有以下代码:
Type t = typeof(UInt64);
var def = Activator.CreateInstance(t);
Console.WriteLine(def.GetType());
string json = "18446744073709551615";
object parsedObject = JsonConvert.DeserializeAnonymousType(json, def);
Console.WriteLine(parsedObject.GetType());
输出为:
System.UInt64
System.Numerics.BigInteger
因为我明确地用 def
喂养 DeserializeAnonymousType
,其类型是 UInt64
,我希望 UInt64
也作为输出,特别是因为 18446744073709551615 是有效的UInt64
值(最大值,当然,但我也检查了 18446744073709551614,它是一样的)。
为什么会这样?我检查了 Newtonsoft Github issues,但什么也没发现(至少,未解决的 issues)。
如何强制我预先知道的正确类型(动态地,我只有 System.Type
)?显然,如果它只发生在 UInt64
时,我可以进行检查并显式转换。
您的问题是 JsonConvert.DeserializeAnonymousType<T>(string value, T anonymousTypeObject)
没有达到您的预期。它不会将 JSON 字符串反序列化为 T anonymousTypeObject
参数的 实际类型 。它将 JSON 字符串反序列化为参数的 声明类型 —— 在您的例子中,是 object
.
从reference source可以看出:
public static T DeserializeAnonymousType<T>(string value, T anonymousTypeObject)
{
return DeserializeObject<T>(value);
}
T anonymousTypeObject
从未实际使用过。相反,目标类型完全是在调用 DeserializeAnonymousType
时通过类型推断指定的——特别是根据代码中变量 def
的声明类型。但是 def
被隐式声明为 object
,因为那是 Activator.CreateInstance(Type type)
被声明为 return 的内容。因此 object
是 Json.NET 将 JSON 反序列化为——某种足以捕获传入 JSON 的 .Net 类型。由于 BigInteger
足以捕获传入的 JSON,Newtonsoft 恰好选择了该类型而不是 Uint64
。
如果你想强制Json.NET反序列化为特定对象的实际具体类型,请使用JsonConvert.DeserializeObject(string value,Type type)
:
object parsedObject = JsonConvert.DeserializeObject(json, def.GetType());
演示 fiddle here.
我使用了这个例子并认为我会把它推进到 classes:
的列表List<_class> listOfClasses = new List<_class>();
var content = response.Content.ReadAsStringAsync().Result;
object parsedObject = JsonConvert.DeserializeAnonymousType(content, Activator.CreateInstance(typeof(_class)));
var _listOfClasses = JsonConvert.DeserializeObject<List<_class>>(parsedObject.ToString());
listOfClasses = _listOfClasses;
这样做是从 API 中使用 TEntity 的列表,然后将其解析回与消费者
匹配的 class