For example, I would like to serialize and deserialize System.Drawing.Font
which is immutable and cannot be altered to suit protobuf-net conventions. In general, is it possible to write some sort of "custom" serializer in protobuf-net?
Edit: Based on the accepted answer, here are examples of proxies for System.Drawing
:
[ProtoContract]
struct ProtoColor
{
[ProtoMember(1, DataFormat=DataFormat.FixedSize)]
public uint argb;
public static implicit operator Color(ProtoColor c)
{ return Color.FromArgb((int)c.argb); }
public static implicit operator ProtoColor(Color c)
{ return new ProtoColor { argb = (uint)c.ToArgb() }; }
}
[ProtoContract()]
class ProtoFont
{
[ProtoMember(1)]
string FontFamily;
[ProtoMember(2)]
float SizeInPoints;
[ProtoMember(3)]
FontStyle Style;
public static implicit operator Font(ProtoFont f) {
return new Font(f.FontFamily, f.SizeInPoints, f.Style);
}
public static implicit operator ProtoFont(Font f) {
return f == null ? null : new ProtoFont {
FontFamily = f.FontFamily.Name,
SizeInPoints = f.SizeInPoints,
Style = f.Style };
}
}
[ProtoContract()]
class ProtoStringFormat
{
[ProtoMember(1, DataFormat=DataFormat.Group)]
StringAlignment Alignment;
[ProtoMember(2)]
StringAlignment LineAlignment;
[ProtoMember(3)]
StringFormatFlags Flags;
public static implicit operator StringFormat(ProtoStringFormat f) {
return new StringFormat(f.Flags) { Alignment = f.Alignment,
LineAlignment = f.LineAlignment };
}
public static implicit operator ProtoStringFormat(StringFormat f) {
return f == null ? null : new ProtoStringFormat() {
Flags = f.FormatFlags, Alignment = f.Alignment,
LineAlignment = f.LineAlignment };
}
}
// Before serializing or deserializing...
static RuntimeTypeModel Model;
static StaticConstructor()
{
Model = TypeModel.Create();
Model.AllowParseableTypes=true;
Model.Add(typeof(Color), false).SetSurrogate(typeof(ProtoColor));
Model.Add(typeof(Font), false).SetSurrogate(typeof(ProtoFont));
Model.Add(typeof(StringFormat), false)
.SetSurrogate(typeof(ProtoStringFormat));
Model.Add(typeof(PointF), true).Add("X", "Y");
}
Yes. Note that many immutable types will be handled by the "auto tuple" code - if it has a constructor that accepts parameters that look just like the public members, it can infer the behaviour from that.
Other than that, you can write your own DTO that has whatever layout / members you need, and add conversion operators (implicit or explicit) to and from your custom DTO and the target type (Font in this case). Your operator would have the code to get from one to the other. Then call:
RuntimeTypeModel.Default.Add(typeof(Font), false)
.SetSurrogate(typeof(YourCustomDTO));
The serializer will use the operators to change between the two types, and use the custom DTO on the wire.
Watch out for the incoming value to the operator being null!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With