Reputation: 2292
I need to add the System.Drawing.Color
to the default model, but its values are readonly, so I tried to do the following :
MetaType colorMeta = RuntimeTypeModel.Default.Add(typeof(Color), true);
MethodInfo methodInfo = typeof(Color).GetMethod("FromArgb", new Type[] { typeof(Int32), typeof(Int32), typeof(Int32), typeof(Int32) });
colorMeta.AddField(1, "A");
colorMeta.AddField(2, "R");
colorMeta.AddField(3, "G");
colorMeta.AddField(4, "B");
colorMeta.SetFactory(methodInfo);
and I get :
InvalidOperationException : Operation is not valid due to the current state of the object
Upvotes: 1
Views: 456
Reputation: 1063499
There's a couple of problems there; firstly, a "factory" in this context would need to be a static method that creates instances of the type, but it does not do this with the values - it is not intended to be used with methods like FromArgb
.
Secondly, protobuf-net won't be able to do much with the A
/ R
/ G
/ B
properties since they lack setters.
Your thinking has merit, though - this is very similar to the existing auto-tuple functionality - the main difference there being that the auto-tuple code wants there to be a constructor that matches all of the obvious members. Color
does not have such a constructor, but it is perhaps worth my looking to see if it is possible to extend the tuple code to allow factory methods instead of just the constructor.
However, for now (without changing any code) there are probably two viable options:
I would probably suggest the latter is easier. For example, the following works (using the fixed 4-byte layout since this should work nicely for all colors):
using ProtoBuf;
using ProtoBuf.Meta;
using System.Drawing;
[ProtoContract]
struct ColorSurrogate
{
public int Value { get { return value; } }
[ProtoMember(1, DataFormat = DataFormat.FixedSize)]
private int value;
public ColorSurrogate(int value) { this.value = value; }
public static explicit operator Color(ColorSurrogate value) {
return Color.FromArgb(value.Value);
}
public static explicit operator ColorSurrogate(Color value) {
return new ColorSurrogate(value.ToArgb());
}
}
[ProtoContract]
class Foo {
[ProtoMember(1)]
public Color Color { get; set; }
}
class Program {
static void Main() {
RuntimeTypeModel.Default.Add(typeof(Color), false)
.SetSurrogate(typeof(ColorSurrogate));
var foo = new Foo { Color = Color.Firebrick };
var clone = Serializer.DeepClone(foo);
}
}
Upvotes: 1