RunFactory为RuntimeTypeModel时的InvalidOperationException

时间:2013-04-29 12:56:27

标签: protobuf-net

我需要将System.Drawing.Color添加到默认模型,但其值只读,所以我尝试执行以下操作:

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);

我得到了:

InvalidOperationException : Operation is not valid due to the current state of the object

1 个答案:

答案 0 :(得分:1)

那里有几个问题;首先,在这种情况下,“工厂”需要是一个静态方法来创建该类型的实例,但它使用这些值执行此操作 - 它不打算用于像FromArgb

其次,protobuf-net无法对A / R / G / B属性执行太多操作,因为它们缺少setter。

但是你的想法是有价值的 - 这与现有的自动元组功能非常相似 - 主要区别在于自动元组代码希望有一个与所有明显成员匹配的构造函数。 Color没有这样的构造函数,但也许值得我查看是否可以扩展元组代码以允许工厂方法而不仅仅是构造函数。

但是,就目前而言(不更改任何代码),可能有两个可行的选择:

  • 告诉模型序列化私有字段,并跳过构造函数
  • 使用代理

我可能会建议后者更容易。例如,以下工作(使用固定的4字节布局,因为这应该适用于所有颜色):

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);
    }
}