Excepción de Protobuf-net con subclases desconocidas

He desarrollado una aplicación que está destinada a enviar datos del cliente al servidor y viceversa, etc., utilizando objetos serializados.

Para esta aplicación, decidí que protobuf-net sería una buena opción (especialmente porque maneja tan bien objetos de longitud variable).

Sin embargo, al enviar un objeto de cliente a servidor o viceversa, todo lo que sé es que el objeto será una clase secundaria de 'ReplicableObject'. Por lo tanto, estoy usando:

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

Donde 'ro' es un objeto de un tipo que subclasifica de ReplicableObject.

Sin embargo, obtengo esta excepción:

Se produjo una excepción no controlada del tipo 'ProtoBuf.ProtoException' en protobuf-net.dll

Información adicional: tipo inesperado encontrado durante la serialización; los tipos deben incluirse con ProtoIncludeAttribute; encontrado MessageObject pasado como ReplicableObject

En este caso particular, estoy intentando enviar un MessageObject.

Como hay poca documentación para protobuf-net, no sé qué hacer. He probado algunos atributos aquí y allá en vano.

Cualquier ayuda apreciada.

Editar: Debo dejar en claro que las subclases podrían ni siquiera ser las que he escrito.

preguntado el 27 de agosto de 11 a las 23:08

Acabo de regresar de unos días fuera. Veré esto más tarde.

1 Respuestas

Protobuf es un formato de serialización basado en contratos, diseñado para ser independiente de la plataforma. Como tal, no El tipo de metadatos se incluye en el cable, ya que no se aplicaría entre plataformas. Incluso la herencia no es parte de la especificación principal de protobuf.

protobuf-net como implementación específica introduce soporte para herencia (a través de algunos humo y espejos), pero idealmente aún debería ser posible definir los tipos esperados por adelantado, exactamente igual que otros serializadores como XmlSerializer or DataContractSerializer. Esto se puede hacer usando [ProtoInclude(...)] para especificar los tipos de hormigón previstos.

Si realmente no puede saber los tipos reales de antemano, también hay una DynamicType opción, que escribe AssemblyQualifiedName en la secuencia. Si está interesado en esta ruta, tenga en cuenta que las características "multiplataforma" del formato comienzan a descomponerse, pero es muy útil para fines de .NET a .NET.

En el más simple, una envoltura como:

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

Envuelva su objeto en que y debería comportarse (al menos en v2; DynamicType no existía en v1). Ejemplo completo:

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

Respondido 30 ago 11, 16:08

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.