Чтобы заставить это работать, вам просто нужно назначить тег (номер), который он будет использовать для идентификации подтипа. В принципе, спецификация проводника «протокольные буферы» не обрабатывает наследование, поэтому protobuf-net достигает этого путем моделирования наследования как инкапсуляции. Вы присваиваете метки свойствам/полям [ProtoMember]
, а подтипы - через [ProtoInclude]
(сравните с [XmlInclude]
).
Обратите внимание, что метки должны быть уникальными в пределах любого одного типа, но они могут быть повторно использованы в подтипов - как показано в примере с помощью обоих уровней с помощью тега 1.
Как так:
using System.Collections.Generic;
using ProtoBuf;
[ProtoContract]
[ProtoInclude(20, typeof(SomeDerived))]
public class SomeBase
{
[ProtoMember(1)]
public string BaseProp { get; set; }
}
[ProtoContract]
public class SomeDerived : SomeBase
{
[ProtoMember(1)]
public int DerivedProp { get; set; }
}
[ProtoContract]
public class SomeEntity
{
[ProtoMember(1)]
public List<SomeBase> SomeList;
}
class Program
{
static void Main()
{
SomeEntity orig = new SomeEntity
{
SomeList = new List<SomeBase> {
new SomeBase { BaseProp = "abc"},
new SomeDerived { BaseProp = "def", DerivedProp = 123}
}
};
var clone = Serializer.DeepClone(orig);
// clone now has a list with 2 items, one each SomeBase and SomeDerived
}
}
Отличный ответ, как всегда! –
2 вопроса: сможет ли кто-нибудь на другом конце провода справиться с этим в Java/C++? и второй вопрос: возможно ли это с .proto? (если оба да, вы можете дать .proto sample? ty –
@David protobuf-net реализует наследование через инкапсуляцию, поэтому SomeBase будет иметь необязательное поле типа SomeDerived, с полем № 20 GetProto/GetSchema проиллюстрирует это. Однако protobuf-net не * генерирует * наследование на уровне codegen (если он начинается с .proto), потому что у .proto нет метафоры для описания такого. –