У меня есть конкретный вариант использования для наследования с использованием 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
{
}
С приведенным ниже определением модели протобуфа:
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; }
}
А также определение модели в соответствии с ним, пытаясь сохранить один и тот же идентификатор для каждого класса, определенного ранее.
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.
![Model types definition](https://i.stack.imgur.com/918nh.png)
Но когда я проверяю значения объектов, я вижу, что FooC десериализован как FooD, а значение D всегда равно 0.
![Deserialized values](https://i.stack.imgur.com/4dIoI.png)
Что я делаю не так? Есть ли способ справиться с этим?
UPDATE
При попытке отладки исходного кода protobuf-net при десериализации FooC в Версии 2 метод RuntimeTypeModel .GetKey () запускается из базового класса (getBaseKey = true), правильно получает FooA1 (key = 2), но в конечном итоге получает FooD объект вместо FooC . Может быть, есть способ обработать этот метод по-другому, чтобы разрешить такой сценарий?
![protobuf debug](https://i.stack.imgur.com/vsyu1.png)