Можно ли добавить новый атрибут ProtoInclude, чтобы не нарушить обратную совместимость
Мы столкнулись с проблемой обратной совместимости, когда мы добавили новый подкласс интерфейса с прототипом, но это означает, что этот объект нельзя открыть в предыдущих версиях.
В общем, все в порядке, все наши десериализованные объекты выполняются отдельно, поэтому неудачные попытки десериализации не могут разрушить все остальное. К сожалению, этот интерфейс сериализуется в списке, поэтому присутствие объекта нового типа в этом классе приведет к тому, что весь список не будет десериализован.
Есть ли способ пометить класс или список в текущей версии, чтобы старая версия просто пропускала те объекты, которые не могут быть удовлетворены.
Просто слишком ясно, мы задаемся вопросом о том, как изменить то, что мы имеем на стороне сериализации этой проблемы.
Тест для репликации исключения:
using System.IO;
using NUnit.Framework;
using ProtoBuf;
namespace UnitTest.ProtoBuf
{
[ProtoContract]
[ProtoInclude(1, typeof(ImplementorInV2))]
internal interface IInterfaceV2
{
}
[ProtoContract]
internal interface IInterfaceV1
{
}
[ProtoContract]
internal class ImplementorInV2 : IInterfaceV2
{
[ProtoMember(1)]
public string Member { get; set; }
}
[TestFixture, Category("Framework")]
internal class ProtoIncludeAddedTest
{
[Test]
public void BasicTest()
{
var a = new ImplementorInV2();
a.Member = "bla bla";
byte[] buffer;
IInterfaceV1 aCopy;
using (var stream = new MemoryStream())
{
Serializer.Serialize(stream, a);
buffer = stream.ToArray();
}
using (var stream = new MemoryStream(buffer))
{
aCopy = Serializer.Deserialize<IInterfaceV1>(stream);
}
}
}
}
1 ответ
В общем: да-иш; в вашем конкретном сценарии - возможно, нет, в основном. Если бы это было наследование классов, оно десериализовалось бы настолько, насколько это возможно, по известной цепочке наследования, т. Е. Если бы вы имели
[ProtoContract]
class Foo {} // v1
а также
[ProtoContract, ProtoInclude(1, typeof(Bar))]
class Foo {}
[ProtoContract]
class Bar : Foo {} // v2
а затем сериализовал Bar
в v2 клиент v1 просто десериализовал бы его как Foo
и игнорировать неожиданные данные. Однако проблема в вашем случае заключается в том, что для интерфейса нет реализации по умолчанию - он ничего не может создать. По сути, существует способ указать тип по умолчанию для создания списков и т. Д., Именно по этой причине, но к тому времени, когда вы развернете, вы можете просто развернуть код v2.