protobuf-net - google protobuf dll
¿Puedo serializar tipos arbitrarios con protobuf-net? (3)
Con todo respeto a la respuesta de Marc Gravell, si te preocupa el tamaño de los datos serializados, debes 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 registrándolo absolutamente de la misma manera:
RuntimeTypeModel.Default.Add(typeof(DateTimeOffset), false).SetSurrogate(typeof(DateTimeOffsetSurrogate));
Estoy intentando serializar algunos objetos con protobuf-net , pero desafortunadamente hacen un uso liberal de DateTimeOffset
, que aún no es compatible con protobuf-net. Esto conduce a un montón de:
No se ha definido ningún serializador para el tipo: System.DateTimeOffset
¿Puedo definir mi propia rutina de serialización para tipos desconocidos? (La misma pregunta se hizo antes, pero su problema se solucionó).
Estoy usando la última versión beta de protobuf-net , v2.0.0.431, bajo .NET 4 si importa. También estoy usando definiciones de tiempo de ejecución, por lo que no tengo forma de especificar de forma declarativa cómo deben manejarse ciertas propiedades.
En caso de que algún desarrollador de F # encuentre esta pregunta, aquí hay una respuesta en F #:
[<ProtoContract>]
type DateTimeOffsetSurrogate() =
[<ProtoMember(1)>]
member val DateTimeString = "" with get, set
static member public op_Implicit(value : DateTimeOffset) : DateTimeOffsetSurrogate =
DateTimeOffsetSurrogate(DateTimeString = value.ToString("o"))
static member public op_Implicit(value : DateTimeOffsetSurrogate) : DateTimeOffset =
DateTimeOffset.Parse(value.DateTimeString)
Es el aspecto op_Implicit
que no es obvio.
También puede adaptar esto para usar la técnica de Max de usar tics para ahorrar espacio.
Edición: aquí se explica cómo agregar el sustituto al modelo de tipo de tiempo de ejecución:
let init() =
ProtoBuf.Meta.RuntimeTypeModel.Default.Add(typedefof<DateTimeOffset>, false).SetSurrogate(typedefof<DateTimeOffsetSurrogate>)
Hay dos formas de abordar el tema de los tipos "comunes" desconocidos; el primero es usar una propiedad shim, por ejemplo, una propiedad que representa el valor como algo similar (una 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 un sustituto , que es un segundo contrato protobuf que se sustituye automáticamente. Los requisitos para utilizar un sustituto son:
- debe haber un operador de conversión definido (implícito o explícito) entre los dos tipos (por ejemplo,
DateTimeOffset
yDateTimeOffsetSurrogate
) - luego utiliza
SetSurrogate(surrogateType)
para educar protobuf-net, por ejemploRuntimeTypeModel.Default.Add(typeof(DateTimeOffset), false).SetSurrogate(typeof(DateTimeOffsetSurrogate));
La propiedad shim es más simple, pero requiere repetición por miembro. El sustituto se aplica automáticamente a todas las instancias del tipo dentro del modelo. El sustituto luego sigue las reglas estándar de protobuf-net, por lo que debe indicar qué miembros se serializarán, etc.
EDITAR: Agregar 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);
}
}
Entonces registralo asi
RuntimeTypeModel.Default.Add(typeof(DateTimeOffset), false).SetSurrogate(typeof(DateTimeOffsetSurrogate));