Protobuf-net - Как пользоваться oneof
Я быстро поискал информацию об использовании
oneof
in, и, похоже, он поддерживается начиная с v2.3.0 , но я не могу найти никаких примеров того, как именно его использовать!
Мои требования довольно просты, и, возможно, это также можно решить с помощью
[ProtoInclude]
но я не совсем уверен, как это будет работать. У меня такой класс:
[ProtoContract]
public class ProgressUIMessage
{
[ProtoMember(1)]
public int Id {get; set;}
[ProtoMember(2)]
public object Message {get; set;}
}
Где
Message
может быть 1 из 8 различных известных типов. Типы вообще не наследуются друг от друга, и хотя код можно изменить, у всех типов нет ничего общего.
С использованием
Google.Protobuf
Я ожидал сделать что-то , где у меня есть свойство с именем
Instrument
это может быть один из двух типов в приведенном выше примере, а затем использовать
InstrumentOneofCase
чтобы выяснить, какой тип мне дали. Но как мне добиться того же в
Protobuf-net
?
РЕДАКТИРОВАТЬ: Я оставлю исходный вопрос как есть, но, возможно, лучший вопрос, к которому может относиться больше людей, - это: как бы вы достигли того же, что и в подобноеэтом примере MS в Protobuf-net? Как с точки зрения написания самого класса, так и с точки зрения определения конкретного типа параметра в конечном итоге?
1 ответ
Чтобы поиграть с этим, нужно взять сообщение из примера MS, который вы цитируете, и пропустить его через protogen, чтобы увидеть, что он делает - что мы можем сделать очень удобно здесь: https://protogen.marcgravell.com/ (примечание I добавляю
syntax = "proto3";
в верхней части файла, который опущен в примере MS).
Это дает нам, среди прочего:
[global::ProtoBuf.ProtoMember(2, Name = @"stock")]
public Stock Stock
{
get => __pbn__instrument.Is(2) ? ((Stock)__pbn__instrument.Object) : default;
set => __pbn__instrument = new global::ProtoBuf.DiscriminatedUnionObject(2, value);
}
public bool ShouldSerializeStock() => __pbn__instrument.Is(2);
public void ResetStock() => global::ProtoBuf.DiscriminatedUnionObject.Reset(ref __pbn__instrument, 2);
private global::ProtoBuf.DiscriminatedUnionObject __pbn__instrument;
[global::ProtoBuf.ProtoMember(3, Name = @"currency")]
public Currency Currency
{
get => __pbn__instrument.Is(3) ? ((Currency)__pbn__instrument.Object) : default;
set => __pbn__instrument = new global::ProtoBuf.DiscriminatedUnionObject(3, value);
}
public bool ShouldSerializeCurrency() => __pbn__instrument.Is(3);
public void ResetCurrency() => global::ProtoBuf.DiscriminatedUnionObject.Reset(ref __pbn__instrument, 3);
Итак, мы видим, что в основном используется условная сериализация, построенная на основе типа. На самом деле существует множество связанных типов с именами
DiscriminatedUnion*
- в зависимости от того, что вам нужно пересечь, но поскольку здесь все типы сообщений:
DiscriminatedUnionObject
у нас работает.
Также есть необязательный параметр «следует использовать перечисление» (как ни странно, «Параметры»), который, если он включен, также добавляет:
public InstrumentOneofCase InstrumentCase => (InstrumentOneofCase)__pbn__instrument.Discriminator;
public enum InstrumentOneofCase
{
None = 0,
Stock = 2,
Currency = 3,
}
Без этого вам пришлось бы использовать
ShouldSerialize*()
методы разрешения активного дела.
Надеюсь, это проясняет, как
oneof
может использоваться с protobuf-net.