Protobuf-net中的默认构造函数约束

时间:2014-09-16 11:45:09

标签: c# protobuf-net

当我运行显示的单元测试时,我在protobuf 反序列化期间得到异常Object does not match target type

我将问题缩小到默认构造函数ContainerForA()

这个默认构造函数在反序列化期间用PropA实例初始化变量ClassA,因为protobuf-net将调用默认构造函数。然后protobuf反序列化器应该使用序列化的ClassB实例覆盖此属性。我想在这一点上会抛出异常。

如果我从默认构造函数ContainerForA()中删除代码,则测试似乎有效。

protobuf-net是否对您在默认构造函数中允许执行的操作有限制?或者我的代码还有其他问题吗?

我正在使用protobuf-net portable 2.0.0.668

[ProtoContract]
[ProtoInclude(101, typeof(IBaseB))]
[ProtoInclude(102, typeof(ClassA))]
public interface IBaseA { }

[ProtoContract]
[ProtoInclude(103, typeof(ClassB))]
public interface IBaseB : IBaseA { }

[ProtoContract]
public class ClassA : IBaseA
{
    [ProtoMember(1)]
    public int PropA { get; set; }
}

[ProtoContract]
public class ClassB : IBaseB
{
    [ProtoMember(2)]
    public string PropB { get; set; }
}

[ProtoContract]
public class ContainerForA
{
    [ProtoMember(3)]
    public IBaseA InstanceOfA { get; set; }

    public ContainerForA()
    {
        InstanceOfA = new ClassA();
    }
}

[TestClass]
public class ProtoTestBed1
{
    [TestMethod]
    public void TestProto()
    {
        var containerForA = new ContainerForA()
        {
            InstanceOfA = new ClassB { PropB = "I'm B"}
        };

        var proto = new ProtobufSerializer();
        var bytes = proto.Serialize(containerForA);
        var containerForADeserialized = proto.Deserialize<ContainerForA>(bytes);

        Debug.WriteLine(containerForADeserialized);
    }
}

2 个答案:

答案 0 :(得分:3)

我不确定这些约束是什么(马克可能会稍微说一下并告诉你)但是有一些解决方法

试试这个:

[ProtoContract(SkipConstructor=true)]
public class ContainerForA
{
    [ProtoMember(3)]
    public IBaseA InstanceOfA { get; set; }

    public ContainerForA()
    {
        InstanceOfA = new ClassA();
    }
}

使用Portable版本再看看这个。不确定如何使用属性执行此操作,但提出了以下解决方案,似乎通过使用工厂方法来工作&#34;撤消&#34;构造函数。

    public class ContainerForA
    {
        public IBaseA InstanceOfA { get; set; }

        public ContainerForA()
        {
            InstanceOfA = new ClassA();
        }

        private static ContainerForA EmptyContainerFactory()
        {
            return new ContainerForA()
            {
                InstanceOfA = null
            };
        }
    }



    static void Main(string[] args)
    {
        var containerForA = new ContainerForA()
        {
            InstanceOfA = new ClassB { PropB = "I'm B" }
        };

        var model = RuntimeTypeModel.Create();
        var baseA = model.Add(typeof(IBaseA), true);
        baseA.AddSubType(101, typeof(IBaseB));
        baseA.AddSubType(102, typeof(ClassA));
        var baseB = model.Add(typeof(IBaseB), true);
        baseB.AddSubType(103, typeof(ClassB));
        var classA = model.Add(typeof(ClassA), true);
        classA.AddField(1, "PropA");
        var classB = model.Add(typeof(ClassB), true);
        classB.AddField(2, "PropB");
        var container = model.Add(typeof(ContainerForA), true);
        container.AddField(3, "InstanceOfA");

        container.SetFactory("EmptyContainerFactory");

        MemoryStream mem = new MemoryStream();
        model.Serialize(mem, containerForA);
        mem.Seek(0, SeekOrigin.Begin);
        var containerForADeserialized = model.Deserialize(mem, null, typeof(ContainerForA));

        Debug.WriteLine(containerForADeserialized);
    }

答案 1 :(得分:0)

项目维护者Marc Gravell证实这是预期的行为:

Protobuf-net不愿意替换实例;

如果子对象/集合/ etc为非null,则会非常难以使用它,而不是重新分配树中的所有内容。

在您的情况下,最简单的修复可能只是在反序列化期间运行构造函数