protobuf-net 序列化为基类

发布于 2024-12-11 11:18:04 字数 1387 浏览 0 评论 0原文

我想使用 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,而不是 基地如我所愿。

我缺少什么?如果我忽略了其他地方的答案,请道歉。我想我问的问题与这个问题相反,尽管我不想通过显式添加字段运行时类型模型

I'd like to use protobuf-net to serialize a derived class as its base class. In other words, I want the serialization process to discard any indication that the type is derived:

[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();
    }
}

I'd like the above program to produce

 Deserialized type: Base
 Deserialized value: public info

but instead I get an exception about "Type is not expected".

If I add [ProtoContract] to Derived, the PublicInfo field isn't set. And if I also add [ProtoInclude(2, typeof(Derived))] to Base then the deserialized type is Derived, not Base as I want.

What am I missing? Apologies if I've overlooked an answer somewhere else. I think I'm asking for something like the opposite of this question, though I'd rather not have to explicitly add fields via the RuntimeTypeModel.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

转身泪倾城 2024-12-18 11:18:04

如果您的层次结构不太复杂,您可以考虑使用序列化成员组合派生类型,而不是从中继承。

[ProtoContract] class Generic {
  [ProtoMember(1)] public string PublicInfo { get; set; }
}

class Specialized {
   public Generic Generic { get; set; }
   public string SecretInfo { get; set; }
}

对象的某些部分是可序列化的,而某些部分是序列化不知道的。将这些混合在一个继承层次结构中并不是一个好主意。因为它不遵循OO的专业化概念。基类是可序列化的,派生类不是,但是对于继承,派生类必须支持基类已经支持的所有内容。

If your hierarchy isn't too complex you could think about composing your derived type with a serialization member instead of inheriting from it.

[ProtoContract] class Generic {
  [ProtoMember(1)] public string PublicInfo { get; set; }
}

class Specialized {
   public Generic Generic { get; set; }
   public string SecretInfo { get; set; }
}

There are some parts of your object that are serializable and some parts are serialization unaware. It's not a good idea to mix these in one inheritance hierarchy. Because it doesn't follow the OO concept of specialization. The base class is serializable, the derived class not, however for inheritance the derived class would have to support everything that the base class already supports.

花桑 2024-12-18 11:18:04

大多数序列化器都会对此感到窒息,因为它们被设计就是为了让您重现开始时的内容。相关问题中提出的答案就足够了,但有点破解,因此确实需要使用RuntimeTypeModel一点巫毒。在这方面,我非常喜欢 DonAndre 的回答中的解决方案,这使得一切都非常干净(并且 Specialized 甚至可以是一个合同,其中包含 GenericSecretInfo 省略)。

唯一要做的事情是让其相信您的派生实际上是代理。代理检测代码目前无法在运行时自定义,但是欺骗它并不难(滥用一些实现知识),即

namespace NHibernate.Proxy {
    internal interface INHibernateProxy {} // pretty spectacularly evil
}
...
class Derived : Base, INHibernateProxy {}

现在,当它发现它无法识别Derived时应该检查常见的代理模式,发现它看起来很像 NHibernate 代理,并使用基本类型。真的很可怕而且又脏。

Most serializers will choke on that, since they are designed to want to allow you to reproduce what you started with. The answer proposed in the related question would suffice, but is a bit of a hack and as such does require a little voodoo with RuntimeTypeModel. In that respect, I quite like the solution in DonAndre's answer, which keeps everything pretty clean (and Specialized could even be a contract, with Generic included and SecretInfo omitted).

The only other thing to do would be to convince it that your Derived is actually a proxy. The proxy detection code is not currently customisable at runtime, however it wouldn't be hard to fool it (abusing some knowledge of the implementation), i.e.

namespace NHibernate.Proxy {
    internal interface INHibernateProxy {} // pretty spectacularly evil
}
...
class Derived : Base, INHibernateProxy {}

now, when it finds it doesn't recognise Derived it should check for common proxy patterns, find it looks a lot like an NHibernate proxy, and use the base-type. Really horrible and grungy.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文