2011-06-06 8 views
9

Marc mencionó en stackoverflow que será posible en v2 de protobuf-net usar el atributo ProtoInclude (o enfoque similar) para serializar/deserializar la jerarquía de clases sin necesidad de especificar cada subtipo en la clase base. ¿Ya está implementado? Tenemos una interfaz de complemento que se puede derivar en bibliotecas externas, por lo que no hay forma de saber cuáles serán los tipos derivados. Sin embargo, podríamos mantener la numeración única entre los tipos, pero no pude encontrar ningún ejemplo en la red, salvo el uso del atributo ProtoInclude, que requiere que se especifique un subtipo.herencia protobuf-net

¿Cómo voy a implementar la herencia con protobuf-net así si no sé cuáles son los subtipos?

Respuesta

16

Si no se puede especificar los subtipos de atributos (ya que no se conoce en tiempo de compilación) tiene 2 opciones (ambos de los cuales sólo se aplican a "v2", disponible como beta):

  1. utilice un RuntimeTypeModel, en lugar de los métodos estáticos Serializer (que ahora son solo un atajo a RuntimeTypeModel.Default); dice el modelo de la herencia (ejemplo siguiente)
  2. DynamicType = true añadir a la [ProtoMember(...)] en cuestión

La segunda es no protobuf muy puro - se incrusta información de tipo, que en realidad no me amor pero las personas solo mantienen pidiendo. El primero es mi opción preferida. Para agregar subtipos en tiempo de ejecución:

var model = TypeModel.Create(); 
var type = model.Add(typeof(YourBaseType), true); 
var subTypeA = model.Add(typeof(SomeSubType), true); 
var subTypeB = model.Add(typeof(SomeOtherSubType), true); 
type.AddSubType(4, typeof(SomeSubType)); 
type.AddSubType(5, typeof(SomeOtherSubType)); 

la true en los medios anteriores "usan reglas normales para agregar propiedades de miembro de forma automática" - también se puede tomar el control de eso y especificar las propiedades (etc) de forma manual, si lo prefiere.

Tenga en cuenta que un TypeModel debe almacenarse en caché y reutilizarse (no creado por objeto que necesita serializar), ya que incluye un código de "emisión" para generar métodos. Reutilizarlo será más rápido y requerirá menos memoria. El modelo de tipo es seguro para subprocesos y se puede utilizar para serializar/deserializar múltiples flujos simultáneamente en diferentes subprocesos.

+0

Muy bien, gracias. Eso es lo que quería hacer, pero no estaba seguro de cómo funcionó exactamente.El mapeo automático de propiedades es un buen toque. Íbamos a hacer eso con los atributos post-compilación de postharp, pero esto es mucho mejor. –

+0

@Heavy para aclarar, en este caso "automático" significa "de algo como XmlElement, DataMember o ProtoMember". There * is * también soporte incorporado para campos implícitos ordenados alfabéticamente pero es más frágil; debe tener cuidado con eso. –

+0

@Marc ** 1) ** ¿Puedo definir algunos subtipos del mismo tipo de base usando atributos y luego agregar algunos más en el tiempo de ejecución? ** 2) ** ¿Por qué son necesarias las líneas 3 y 4 en su código? ¿No son redundantes si agrega las líneas 5ª y 6ª? – Rotem

4

para ampliar aún más la respuesta de Marc, se ocupa específicamente de RuntimeTypeModel, esta es una forma de escribirlo:

RuntimeTypeModel.Default[typeof(BaseClass)].AddSubType(20, typeof(DerivedClass)); 

Si tiene más clases derivadas de clases derivadas, los relacionan como esto

RuntimeTypeModel.Default[typeof(DerivedClass)].AddSubType(20, typeof(DerivedFromDerivedClass)); 

Y así sucesivamente.
Puede usar Serializer.Serialize(file,object), como lo haría normalmente con protobuf-net.
Esto funciona en proyectos y espacios de nombres.

+0

BRILLIANT muchas gracias. Esto funciona perfecto para mi escenario. – Asheh

2

Mediante la adición de método de extensión ayudante:

public static class RuntimeTypeModelExt 
{ 
    public static MetaType Add<T>(this RuntimeTypeModel model) 
    { 
     var publicFields = typeof(T).GetFields().Select(x => x.Name).ToArray(); 
     return model.Add(typeof(T), false).Add(publicFields); 
    } 
} 

Puede optimizar el registro subtipo de esta manera:

private static RuntimeTypeModel CreateModel() 
{ 
    var model = TypeModel.Create(); 
    model.Add<ExportInfo>(); 
    model.Add<RegistrationInfo>(); 
    model.Add<FactorySetupInfo>() 
     .AddSubType(101, model.Add<ServiceSetupInfo>().Type) 
     .AddSubType(102, model.Add<GenericWrapperSetupInfo>().Type) 
     .AddSubType(103, model.Add<DecoratorSetupInfo>().Type); 
    return model; 
}