使用MessagePack序列化含JObject的Dictionary<string,object>报错如何解决?
解决MessagePack序列化JObject时的泛型约束错误
问题场景
需要将任意类序列化为二进制格式,因BinaryFormatter已被弃用选择MessagePack,但序列化包含JObject的Dictionary<string, object>时抛出错误。
代码示例
public class Foo { public Dictionary<string, object> Bar { get; set; } } var foo = new Foo { Bar = new Dictionary<string, object>() }; foo.Bar.Add("binding", JObject.Parse(@"{ ""source"": ""EventRegistrationFormDataSource"", ""inputs"": { ""sourceType"": { ""value"": ""msevtmgt_event"" } }, ""outputPath"": ""msevtmgt_description"", ""outputType"": ""memo"" }")); var options = TypelessContractlessStandardResolver.Options; MessagePackSerializer.Serialize(foo, options);
错误信息
System.ArgumentException: 泛型参数[0]“Newtonsoft.Json.Linq.JContainer”违反了“MessagePack.Formatters.NonGenericListFormatter`1[T]”的类型约束。 堆栈跟踪: RuntimeTypeHandle.Instantiate(RuntimeType inst) RuntimeType.MakeGenericType(Type[] instantiation) --- 内部异常堆栈跟踪结束 --- RuntimeType.ValidateGenericArguments(MemberInfo definition, RuntimeType[] genericArguments, Exception e) RuntimeType.MakeGenericType(Type[] instantiation) DynamicGenericResolverGetFormatterHelper.GetFormatter(Type t) FormatterCache`1.cctor() --- 来自之前位置的堆栈跟踪结束 --- FormatterResolverExtensions.Throw(TypeInitializationException ex) Serialize(Byte[][], Object[], MessagePackWriter&, JProperty, MessagePackSerializerOptions) <4 more frames...> DictionaryFormatterBase`5.Serialize(MessagePackWriter& writer, TDictionary value, MessagePackSerializerOptions options) Serialize(Byte[][], Object[], MessagePackWriter&, Foo, MessagePackSerializerOptions) AnonymousSerializableFormatter`1.Serialize(MessagePackWriter& writer, T value, MessagePackSerializerOptions options) MessagePackSerializer.Serialize[T](MessagePackWriter& writer, T value, MessagePackSerializerOptions options)
解决方案
错误根源是MessagePack默认解析器无法处理Newtonsoft.Json.Linq系列类型(如JObject、JContainer),这些类型不满足NonGenericListFormatter的泛型约束。以下是三种可行解决方式:
1. 自定义JObject格式化器
实现专门处理JObject的格式化器,序列化时将其转为字典,反序列化时再转回JObject:
public class JObjectMessagePackFormatter : IMessagePackFormatter<JObject> { public void Serialize(ref MessagePackWriter writer, JObject value, MessagePackSerializerOptions options) { var dict = value.ToObject<Dictionary<string, object>>(); options.Resolver.GetFormatter<Dictionary<string, object>>().Serialize(ref writer, dict, options); } public JObject Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) { var dict = options.Resolver.GetFormatter<Dictionary<string, object>>().Deserialize(ref reader, options); return JObject.FromObject(dict); } }
注册格式化器到解析器:
var options = MessagePackSerializerOptions.Create(new CompositeResolver( new IMessagePackFormatter[] { new JObjectMessagePackFormatter() }, new IFormatterResolver[] { TypelessContractlessStandardResolver.Instance } )); MessagePackSerializer.Serialize(foo, options);
2. 提前转换JObject为字典
如果不需要保留JObject类型,添加到字典前直接转为Dictionary<string, object>:
var jsonString = @"{ ""source"": ""EventRegistrationFormDataSource"", ""inputs"": { ""sourceType"": { ""value"": ""msevtmgt_event"" } }, ""outputPath"": ""msevtmgt_description"", ""outputType"": ""memo"" }"; foo.Bar.Add("binding", JObject.Parse(jsonString).ToObject<Dictionary<string, object>>());
3. 使用MessagePack的Newtonsoft.Json扩展库
安装MessagePack.NewtonsoftJson包后,直接使用现成的解析器处理JObject:
var options = MessagePackSerializerOptions.Create(new CompositeResolver( new IFormatterResolver[] { NewtonsoftJsonResolver.Instance }, new IFormatterResolver[] { TypelessContractlessStandardResolver.Instance } )); MessagePackSerializer.Serialize(foo, options);
内容的提问来源于stack exchange,提问作者Ondrej Svejdar
相关产品推荐
相关产品推荐

