我正在尝试一种方法来确定给定类型是否可以通过protobuf-net正确序列化。理想情况下,如果protobuf-net可以正确处理类型,我会编写一个返回true
的函数。
“正确”是指类型的非null实例将序列化为非零个字节。我知道序列化为零字节在protobuf中是完全有效的,但是我有兴趣检测不应真正序列化为零字节的情况。
我在GitHub页面"Type Support" section上查看了this answer,并浏览了源代码(主要是与RuntimeTypeModel相关的东西)。我以前尝试的一种解决方案是这样的:
public bool WillSerialize<T>()
{
var t = typeof(T);
// If the RuntimeTypeModel doesn't know about T, it can't serialize
var canSerialize = Serializer.NonGeneric.CanSerialize(t);
if( !canSerialize ) return false;
// If the RuntimeTypeModel has fields for the given type, they
// will be serialized.
var hasFields = RuntimeTypeModel.Default[t].GetFields().Any();
return hasFields;
}
据我所知,问题在于CanSerialize
仅针对RuntimeTypeModel中的类型返回true
(我相信它只是检查RTM中是否存在)。尽管false
(和其他原语)可以被很好地序列化,但对于类似uint
的类型,它返回uint
。另外,通常是由于开发人员错误,我们可以通过首先调用PrepareSerializer<T>
来“欺骗” RTM,使其认为可以正确地序列化类型。
如果我们错误地准备了一个没有任何[ProtoMember]
字段(或有但没有[ProtoAttribute]
的字段),则CanSerialize
将返回true
。这是第二个测试要抓住的情况。如果RTM的MetaType
带有为给定的T
定义的字段,那么我们可以假定它将被正确地序列化。如果没有,我们的protobuf-net包装器会发出警告消息。此处的缺陷是默认支持的类型(例如Dictionary<TKey, TValue>
)在这两个测试中均无法通过。
查看了源代码并看到了knownCodes
(和整个ProtoTypeCode
之类的东西之后,似乎实现我想要的最简单的方法就是构建自己的这样的版本列出并检查它。如果该类型不存在于该列表中,那么我将运行上面的代码。这似乎大体上是完整的,但是省略了通用的集合类型之类的东西。
在我尝试将所有这些一起破解之前,是否有人建议采用更好,更规范的方式进行此类检查?我是否在做出完全错误的假设?谢谢!