【发布时间】:2019-05-30 10:49:51
【问题描述】:
我有一个使用 protobuf-net 进行继承的特定用例,我不知道(如果可能的话)如何处理。
假设我们有这些示例类(将其标记为版本 1):
public class FooA
{
public double A { get; set; }
public double B { get; set; }
}
public class FooB : FooA
{
public double C { get; set; }
}
public class FooC : FooB
{
}
public class FooD : FooC
{
public double D { get; set; }
}
public class FooA1 : FooA
{
}
使用以下 protobuf 的模型定义:
Model = RuntimeTypeModel.Create();
Model.Add(typeof(FooA), false)
.AddSubType(201, typeof(FooB))
.AddSubType(202, typeof(FooA1))
.Add(1, "A")
.Add(2, "B");
Model[typeof(FooB)]
.AddSubType(201, typeof(FooC))
.Add(1, "C");
Model[typeof(FooC)]
.AddSubType(201, typeof(FooD));
Model[typeof(FooD)]
.Add(1, "D");
我将它们序列化如下
FooA a = new FooA() {A = 10, B = 20};
FooB b = new FooB() {A = 10, B = 20, C = 30};
FooA1 b1 = new FooA1() {A = 100, B = 200};
FooC c = new FooC() {A = 10, B = 20, C = 30};
FooD d = new FooD() {A = 10, B = 20, C = 30, D = 40};
using (var stream = File.Open(fileName, FileMode.Create, FileAccess.Write))
{
SerializeWithLengthPrefix(stream, a);
SerializeWithLengthPrefix(stream, b);
SerializeWithLengthPrefix(stream, b1);
SerializeWithLengthPrefix(stream, c);
SerializeWithLengthPrefix(stream, d);
}
辅助方法
public void SerializeWithLengthPrefix<T>(Stream stream, T obj)
{
var serializationContext = new ProtoBuf.SerializationContext() { Context = this };
Model.SerializeWithLengthPrefix(stream, obj, typeof(T), PrefixStyle.Base128, 1, serializationContext);
}
public T DeserializeWithLengthPrefix<T>(Stream stream, out long bytesRead, out bool haveObject)
{
var serializationContext = new ProtoBuf.SerializationContext() { Context = this };
return (T)Model.DeserializeWithLengthPrefix(stream, null, typeof(T), PrefixStyle.Base128, 1, null, out bytesRead, out haveObject, serializationContext);
}
现在我需要以这种方式更改继承层次结构(将其标记为版本 2):
public class FooA
{
public double A { get; set; }
public double B { get; set; }
}
public class FooB : FooA
{
public double C { get; set; }
}
public class FooC : FooA1/*FooB*/
{
public double C { get; set; }
}
public class FooD : FooC
{
public double D { get; set; }
}
public class FooA1 /*: FooA*/
{
public double A { get; set; }
public double B { get; set; }
}
还有根据它的模型定义,尝试为之前定义的每个类保留相同的 id。
Model = RuntimeTypeModel.Create();
Model.Add(typeof(FooA), false)
.AddSubType(201, typeof(FooB))
//.AddSubType(202, typeof(FooA1))
.Add(1, "A")
.Add(2, "B");
Model.Add(typeof(FooA1), false)
.Add(1, "A")
.Add(2, "B");
Model[typeof(FooB)]
//.AddSubType(201, typeof(FooC))
.Add(1, "C");
Model[typeof(FooA1)]
.AddSubType(201, typeof(FooC));
Model[typeof(FooC)]
.Add(1, "C")
.AddSubType(201, typeof(FooD));
Model[typeof(FooD)]
.Add(1, "D");
现在我反序列化使用版本 1 存储的文件并检查模型中定义的类型:它们与版本 1 序列化期间的类型相同。
但是当我检查对象值时,我看到 FooC 已被反序列化为 FooD 并且 D 值始终等于 0。
我做错了什么?有办法处理吗?
更新
FooC 用版本 2 反序列化时尝试调试 protobuf-net 源代码,方法 RuntimeTypeModel.GetKey() 从基类(getBaseKey =true),正确获得 FooA1 (key=2) 但最终它获得 FooD 对象而不是 FooC。也许有办法以不同的方式处理这种方法以允许这样的场景?
【问题讨论】:
标签: c# serialization hierarchy protobuf-net