Protobuf网络中的默认构造函数约束

本文关键字:构造函数 约束 默认 网络 Protobuf | 更新日期: 2023-09-27 18:22:05

I在运行所示的单元测试时,在protobuf反序列化期间收到异常Object does not match target type

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

这个默认构造函数在反序列化过程中用ClassA的实例初始化变量PropA,因为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);
    }
}

Protobuf网络中的默认构造函数约束

我不确定限制是什么(Mark可能会稍后告诉你),但有解决办法

试试这个:

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

使用Portable版本对此进行了另一次查看。不知道如何使用属性来实现这一点,但提出了以下解决方案,该解决方案似乎是通过使用工厂方法来"撤消"构造函数来实现的。

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

项目维护人员Marc Gravell确认这是预期行为:

Protobuf-net倾向于不替换实例;

如果子对象/collection/etc不是null,它会非常努力地使用它,而不是重新分配树中的所有内容。

在您的情况下,最简单的修复方法可能是简单地而不是在反序列化

期间运行构造函数