Можно ли добавить новый атрибут 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.

Другие вопросы по тегам