2011-08-12 8 views
19

Estoy tratando de serializar algunos objetos con protobuf-net, pero lamentablemente hacen uso liberal de DateTimeOffset, que aún no es compatible con protobuf-net. Esto lleva a un montón de:¿Puedo serializar tipos arbitrarios con protobuf-net?

Sin serializador definidos para el tipo: System.DateTimeOffset

¿Puedo definir mi propia rutina de serialización de tipos desconocidos? (El same question se le preguntó anteriormente, pero su problema fue solucionado.)

Estoy utilizando el último protobuf-net beta, v2.0.0.431, en .NET 4 si es necesario. También estoy usando definiciones de tiempo de ejecución, por lo que no tengo manera de especificar de forma declarativa cómo se deben manejar ciertas propiedades.

Respuesta

24

Hay dos formas de abordar el problema de los tipos "comunes" desconocidos; el primero es el uso de una propiedad de cuña, por ejemplo una propiedad que representa el valor como algo similar (un string o long por ejemplo):

[ProtoMember(8)] 
public string Foo { 
    get { ... read from the other member ... } 
    set { ... assign the other member ... } 
} 

El otro enfoque es una sustituto, que es un segundo protobuf contrato que se sustituye automáticamente. Los requisitos para utilizar un sustituto son:

  • Tiene que ser un operador definido conversión (implícita o explict) entre los dos tipos (por ejemplo, DateTimeOffset y DateTimeOffsetSurrogate)
  • a continuación, utiliza SetSurrogate(surrogateType) para educar protobuf-net , por ejemplo RuntimeTypeModel.Default.Add(typeof(DateTimeOffset), false).SetSurrogate(typeof(DateTimeOffsetSurrogate));

la propiedad shim es más simple, pero requiere repetición por miembro. El suplente se aplica automáticamente a todas las instancias del tipo dentro del modelo. El sustituto continuación, sigue las reglas protobuf-net estándar, lo que indicaría que los miembros serializar, etc.

EDIT: Adición de ejemplo de código

using System; 
using ProtoBuf; 

[ProtoContract] 
public class DateTimeOffsetSurrogate 
{ 
    [ProtoMember(1)] 
    public string DateTimeString { get; set; } 

    public static implicit operator DateTimeOffsetSurrogate(DateTimeOffset value) 
    { 
     return new DateTimeOffsetSurrogate {DateTimeString = value.ToString("u")}; 
    } 

    public static implicit operator DateTimeOffset(DateTimeOffsetSurrogate value) 
    { 
     return DateTimeOffset.Parse(value.DateTimeString); 
    } 
} 

A continuación, registrarlo como esto

RuntimeTypeModel.Default.Add(typeof(DateTimeOffset), false).SetSurrogate(typeof(DateTimeOffsetSurrogate)); 
+2

Todo bien, excepto que debería ser 'value.ToString ("O")', 'no "u" '. De lo contrario, perderá la información de compensación (zona horaria). –

+0

¿Cómo otras bibliotecas de protobuf deserializarían el resultado de esto? Si tuvieras un padre de la clase con una propiedad de tipo DateTimeOffset, ¿la otra biblioteca también necesitará un tipo sustituto con una propiedad de cadena? o puede la clase Parent en el otro sistema simplemente usar un tipo de cadena para la propiedad (asumiendo en otro idioma que no tiene un tipo DateTimeOffset)? –

+0

ejemplo: https://gist.github.com/rushfrisby/4377bb0efc1478c14221 –

14

Con todo lo que respecta a la respuesta de Marc Gravell, si le importa el tamaño de los datos serializados, debe usar la siguiente clase sustituta. El tamaño de salida es de 21 bytes en lugar de 35 bytes.

using System; 
using ProtoBuf; 

[ProtoContract] 
public class DateTimeOffsetSurrogate 
{ 
    [ProtoMember(1)] 
    public long DateTimeTicks { get; set; } 
    [ProtoMember(2)] 
    public short OffsetMinutes { get; set; } 

    public static implicit operator DateTimeOffsetSurrogate(DateTimeOffset value) 
    { 
     return new DateTimeOffsetSurrogate 
     { 
      DateTimeTicks = value.Ticks, 
      OffsetMinutes = (short)value.Offset.TotalMinutes 
     }; 
    } 

    public static implicit operator DateTimeOffset(DateTimeOffsetSurrogate value) 
    { 
     return new DateTimeOffset(value.DateTimeTicks, TimeSpan.FromMinutes(value.OffsetMinutes)); 
    } 
} 

Y luego registrarlo absolutamente la misma manera:

RuntimeTypeModel.Default.Add(typeof(DateTimeOffset), false).SetSurrogate(typeof(DateTimeOffsetSurrogate)); 
+0

No entiendo muy bien cómo usar esto en mi caso.Estoy tratando de serializar la clase System.Data.DataSet. Realmente apreciaría una pequeña pista. –

+0

@iknownothing No creo que sea fácil de hacer: System.Data.DataSet es mucho más sofisticado que DateTimeOffset –

Cuestiones relacionadas