Обходной путь для Protobuf- NET I Расширяемое наследование не поддерживается - PullRequest
1 голос
/ 23 апреля 2020

Я десериализирую данные буфера протокола, используя Protobuf- NET, и имею дело с несколькими файлами Proto, которые идентичны, но имеют немного отличающиеся расширения. По сути, каждый канал Proto идентичен на 99%, а затем имеет 1 или 2 поля, отличающиеся друг от друга, которые предоставляются как расширения для каждого. Таким образом, я получил несколько классов Proto, которые на 99% идентичны.

Логически я хочу добавить наследование к сгенерированным C# прото-файлам, чтобы избежать 99% избыточного кода, разбирающего каждый фид. Проблема в том, что я получаю следующую ошибку при десериализации:

System.NotSupportedException
  HResult=0x80131515
  Message=IExtensible is not supported in structs or classes with inheritance
  Source=protobuf-net
  StackTrace:
   at ProtoBuf.Serializers.TypeSerializer..ctor(TypeModel model, Type forType, Int32[] fieldNumbers, IProtoSerializer[] serializers, MethodInfo[] baseCtorCallbacks, Boolean isRootType, Boolean useConstructor, CallbackSet callbacks, Type constructType, MethodInfo factory) in C:\code\protobuf-net\src\protobuf-net\Serializers\TypeSerializer.cs:line 97
   at ProtoBuf.Meta.MetaType.BuildSerializer() in C:\code\protobuf-net\src\protobuf-net\Meta\MetaType.cs:line 480
   at ProtoBuf.Meta.MetaType.get_Serializer() in C:\code\protobuf-net\src\protobuf-net\Meta\MetaType.cs:line 372
   at ProtoBuf.Meta.RuntimeTypeModel.Deserialize(Int32 key, Object value, ProtoReader source) in C:\code\protobuf-net\src\protobuf-net\Meta\RuntimeTypeModel.cs:line 802
   at ProtoBuf.Meta.TypeModel.DeserializeCore(ProtoReader reader, Type type, Object value, Boolean noAutoCreate) in C:\code\protobuf-net\src\protobuf-net\Meta\TypeModel.cs:line 718
   at ProtoBuf.Meta.TypeModel.Deserialize(Stream source, Object value, Type type, SerializationContext context) in C:\code\protobuf-net\src\protobuf-net\Meta\TypeModel.cs:line 590
   at ProtoBuf.Serializer.Deserialize[T](Stream source) in C:\code\protobuf-net\src\protobuf-net\Serializer.cs:line 68

Так что может показаться, что этот сценарий не поддерживается. Теперь неясно, относится ли это к использованию IExtensible в базовом классе или в производном классе. Базовый класс должен оставаться расширяемым, так как я применяю несколько расширений, а классы расширения / производные - нет.

У меня есть код, подобный приведенному ниже, взятый из этого поста . Теперь, прежде чем кто-то пометит его как «Дубликат» - это не потому, что мой вопрос совершенно другой. В то время как его OP спрашивает о назначении IExtensible и последствиях его неиспользования, я спрашиваю о любом возможном обходном пути или решении для описанного выше варианта использования.

[ProtoBuf.ProtoInclude(1000, typeof(DerivedClass))]
public partial class BaseClass : ProtoBuf.IExtensible 
{ 
    ... 
    private IExtension extensionObject;
    IExtension IExtensible.GetExtensionObject(bool createIfMissing)
    {
        return Extensible.GetExtensionObject(ref extensionObject, createIfMissing);        
    }
}    

public partial class DerivedClass : BaseClass, ProtoBuf.IExtensible
{
    ... 
    private IExtension extensionObject;
    IExtension IExtensible.GetExtensionObject(bool createIfMissing)
    {
        return Extensible.GetExtensionObject(ref extensionObject, createIfMissing);        
    }
}   

var baseObject = new MyClass { ... };    
DerivedClass derivedObject;
using (var stream = new MemoryStream())
{
    Serializer.Serialize(stream, baseObject);  // throws runtime exception
    stream.Seek(0, SeekOrigin.Begin);
    derivedObject = Serializer.Deserialize<DerivedClass>(stream);
}

Вопрос: как мне добиться наследования по описанному выше сценарию? Я готов изменить производный класс, любую другую работу, которую вы можете предложить, или даже использовать другую. NET Библиотека Protobuf. * ​​1017 *

1 Ответ

1 голос
/ 23 апреля 2020

Основная проблема здесь заключается в том, что существует коллизия:

  • protobuf- net реализует наследование в protobuf (у которого нет наследования), моделируя его как несколько сообщений (по одному на тип) и oneof в каждой точке принятия решения
  • в protobuf, каждое сообщение может иметь расширения
  • , но сейчас реализация расширений в protobuf- net относится к объекту
  • , поэтому было бы неясно, к какому сообщению вы хотите применить расширение

Я думал о расширении API, чтобы оно отслеживало расширения против логического типа (который сопоставляется с сообщением), но это сложно и потребует времени для добавления.

Большинство других инструментов protobuf вообще не поддерживают наследование, поэтому я сомневаюсь, что вы найдете этот жизнеспособный обходной путь.

Итак: вот почему его нет; это на самом деле не делает вас обходным путем, извините. Единственное «исправление» здесь - «потратить время на реализацию сложности хранения и поиска расширений для каждого типа»

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...