Исключение Protobuf-net с неизвестными подклассами - PullRequest
1 голос
/ 28 августа 2011

Я разработал приложение, предназначенное для отправки данных с клиента на сервер и обратно и т. Д. С использованием сериализованных объектов.

Для этого приложения я решил, что protobuf-net будет хорошим вариантом (особенно если он так хорошо обрабатывает объекты переменной длины).

Однако, при отправке объекта с клиента на сервер или наоборот, все, что я знаю, это то, что объект будет каким-то дочерним классом ReplicableObject. Следовательно, я использую:

Serializer.SerializeWithLengthPrefix(stream, ro, PrefixStyle.Base128);

Где 'ro' - это объект типа, который является подклассом из ReplicableObject.

Однако я получаю это исключение:

Произошло необработанное исключение типа 'ProtoBuf.ProtoException' в Protobuf-net.dll

Дополнительная информация: во время сериализации обнаружен неожиданный тип; типы должны быть включены в ProtoIncludeAttribute; найдено MessageObject передается как ReplicableObject

В данном конкретном случае я пытаюсь отправить MessageObject .

Поскольку для protobuf-net очень мало документации, я застрял на том, что делать. Я попробовал несколько атрибутов здесь и там безрезультатно.

Любая помощь приветствуется.

Редактировать: Я должен дать понять, что подклассы могут даже не быть теми, которые я написал.

1 Ответ

1 голос
/ 30 августа 2011

Protobuf - это формат сериализации на основе контракта, разработанный для обеспечения независимости от платформы. Таким образом, метаданные типа no включены в провод, поскольку они не будут применяться между платформами. Даже наследование не является частью спецификации ядра protobuf. * ​​1003 *

protobuf-net как специфическая реализация вводит поддержку наследования (через дым и зеркала), но в идеале все же должно быть возможно заранее определить ожидаемые типы - точно так же, как другие сериализаторы как XmlSerializer или DataContractSerializer. Это можно сделать с помощью [ProtoInclude(...)] для указания ожидаемых конкретных типов.

Если вы действительно не можете заранее определить фактические типы, существует также опция DynamicType, которая записывает AssemblyQualifiedName в поток. Если вас интересует этот маршрут, обратите внимание, что «кроссплатформенные» возможности формата начинают выходить из строя, но он очень полезен для целей .NET-to-.NET.

В самом простом, обертка, такая как:

[ProtoContract]
public class SomeWrapper {
     [ProtoMember(1, DynamicType = true)]
     public object Value {get;set;}
}

Оберните ваш объект в , чтобы и он должен себя вести (по крайней мере, в v2; DynamicType не существовал в v1). Полный пример:

[TestFixture]
public class SO7218127
{
    [Test]
    public void Test()
    {
        var orig = new SomeWrapper {Value = new SubType { Foo = 123, Bar = "abc"}};
        var clone = Serializer.DeepClone(orig);
        Assert.AreEqual(123, orig.Value.Foo);
        Assert.AreEqual("abc", ((SubType) clone.Value).Bar);
    }
    [ProtoContract]
    public class SomeWrapper
    {
        [ProtoMember(1, DynamicType = true)]
        public BaseType Value { get; set; }
    }
    [ProtoContract]
    public class BaseType
    {
        [ProtoMember(1)]
        public int Foo { get; set; }
    }
    [ProtoContract]
    public class SubType : BaseType
    {
        [ProtoMember(2)]
        public string Bar { get; set; }
    }
}
...