最近在开发 OPC UA 组件时,我遇到了一个有趣的问题:在将内存字典应用于规则引擎并触发工作流后,发现内存字典 Dictionary<string, object>
中的 object
类型值从 int16
自动提升到了 int32
。经过排查,问题只出现在使用 WorkflowCore 的持久化功能时(如果是内存模式则不会出现,因为无需序列化)。
具体原因是,WorkflowCore 会将 Data
中的值序列化后存入数据库或其他持久化存储中。在触发工作流时,这些值会被反序列化回对象。由于序列化和反序列化的过程,object
类型的值会丢失其原始数据类型,导致 int16
自动提升为 int32
。即使在 SerializerSettings
中设置了 TypeNameHandling = TypeNameHandling.All
,也无法避免这个问题。TypeNameHandling
顶多能推断到 object
,却无法准确还原 object
底层的具体数据类型。
总结来说,在使用 Newtonsoft.Json 进行序列化和反序列化时,如果对数据类型有严格要求,建议避免使用 object
类型,而应尽量使用具体的数据类型。否则,可能会导致数据类型丢失或发生意外变化。
这个问题,我已经去了Newtonsoft.Json组件GitHub仓库提起issues
如下https://github.com/JamesNK/Newtonsoft.Json/issues/3000
另外复现代码我提交到我的GitHub仓库https://github.com/peijiehuang/NewtonsoftBug
using Newtonsoft.Json;
namespace NewtonsoftBug
{
internal class Program
{
private static JsonSerializerSettings SerializerSettings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All,
ObjectCreationHandling = ObjectCreationHandling.Replace,
};
static void Main(string[] args)
{
var data1 = new Dictionary<string, object>
{
{ "TEST", (Int16)123 },
{ "TEST2", (Int128)123 },
};
//还没序列化前打印出来的数据类型还是正确的
foreach (var item in data1)
{
Console.WriteLine("data1:" + item.Value.GetType());
}
Console.WriteLine();
Console.WriteLine();
//最多只能推断到数据类型是object,而不是继续推断下去,把底层的数据类型记录起来
var jsonStr = JsonConvert.SerializeObject(data1, SerializerSettings);
Console.WriteLine(jsonStr);
Console.WriteLine();
Console.WriteLine();
//反序列化
var data2 = JsonConvert.DeserializeObject<Dictionary<string, object>>(jsonStr, SerializerSettings);
//反序列化后数据类型已经提升了,int16 > int32 、int128更过分直接成了字符串
foreach (var item in data2)
{
Console.WriteLine("data2:" + item.Value.GetType());
}
}
}
}