我想使用protobuf-net将派生类序列化为其基类。换句话说,我希望序列化过程丢弃任何类型派生的指示:
[ProtoContract]
class Base
{
[ProtoMember(1)]
public string PublicInfo { get; set; }
}
class Derived : Base
{
public string SecretInfo { get; set; }
}
class Program
{
static void Main(string[] args)
{
Derived d = new Derived()
{
PublicInfo = "public info",
SecretInfo = "secret info"
};
using (var ms = new MemoryStream())
{
Serializer.NonGeneric.Serialize(ms, d as Base);
ms.Seek(0, SeekOrigin.Begin);
Base deserialized = Serializer.Deserialize<Base>(ms);
Console.WriteLine("Deserialized type: " + deserialized.GetType());
Console.WriteLine("Deserialized value: " + deserialized.PublicInfo);
}
Console.ReadLine();
}
}
我想要上面的程序来制作
Deserialized type: Base
Deserialized value: public info
但我得到一个关于“不期望类型”的例外。
如果我将[ProtoContract]
添加到Derived
,则不会设置PublicInfo
字段。如果我还将[ProtoInclude(2, typeof(Derived))]
添加到Base
,则反序列化类型为Derived
,而不是Base
。
我错过了什么?如果我在其他地方忽略了答案,请道歉。我想我要求的是与this question相反的内容,但我不想通过RuntimeTypeModel
明确添加字段。
答案 0 :(得分:4)
如果您的层次结构不是太复杂,您可以考虑使用序列化成员来编写派生类型,而不是继承它。
[ProtoContract] class Generic {
[ProtoMember(1)] public string PublicInfo { get; set; }
}
class Specialized {
public Generic Generic { get; set; }
public string SecretInfo { get; set; }
}
您的对象的某些部分是可序列化的,而某些部分是序列化未发现的。在一个继承层次结构中混合使用它们并不是一个好主意。因为它不遵循专业化的OO概念。基类是可序列化的,派生类不是,但是对于继承,派生类必须支持基类已经支持的所有内容。
答案 1 :(得分:3)
大多数序列化程序会阻塞它,因为它们是设计的,希望允许您重现您的开始。相关问题中提出的答案足够,但有点像黑客,因此 需要RuntimeTypeModel
的小巫术。在这方面,我非常喜欢DonAndre's answer中的解决方案,它可以保持一切非常干净(Specialized
甚至可以是合同,其中包含Generic
并省略SecretInfo
。
要做的唯一其他事情就是说服你的Derived
实际上是代理。代理检测代码目前无法在运行时进行定制,但是不容易欺骗它(滥用一些实施知识),即
namespace NHibernate.Proxy {
internal interface INHibernateProxy {} // pretty spectacularly evil
}
...
class Derived : Base, INHibernateProxy {}
现在,当它发现它无法识别Derived
时,它应检查常见的代理模式,发现它看起来很像NHibernate代理,并使用基类型。非常恐怖和蹩脚。