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);
}
}
我不确定限制是什么(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,它会非常努力地使用它,而不是重新分配树中的所有内容。
在您的情况下,最简单的修复方法可能是简单地而不是在反序列化