Несколько опций Джона покрывают простейшие настройки, особенно если вам нужна межплатформенная поддержка.На стороне .NET (чтобы гарантировать, что вы не сериализуете ненужные значения), просто верните null
из любого свойства, которое не совпадает, например:
public object Value { get;set;}
[ProtoMember(1)]
public int? ValueInt32 {
get { return (Value is int) ? (int)Value : (int?)null; }
set { Value = value; }
}
[ProtoMember(2)]
public string ValueString {
get { return (Value is string) ? (string)Value : null; }
set { Value = value; }
}
// etc
Вы также можете сделать то же самоеиспользуйте шаблон bool ShouldSerialize*()
, если вам не нравятся нули.
Оберните это в class
, и вы можете использовать его либо на уровне поля, либо на уровне списка.Вы упоминаете оптимальную производительность;Единственная дополнительная вещь, которую я могу предложить, это, возможно, рассмотреть возможность рассматривать ее как «группу», а не как «суб-сообщение», так как это легче кодировать (и так же легко декодировать, если вы ожидаете данные).Чтобы сделать это, используйте формат данных Grouped
через [ProtoMember]
, то есть
[ProtoMember(12, DataFormat = DataFormat.Group)]
public MyVariant Foo {get;set;}
Однако разница здесь может быть минимальной - но она позволяет избежать некоторого обратного отслеживания в выходном потоке для исправлениядлины.В любом случае, с точки зрения служебных данных , «submessage» займет как минимум 2 байта;«по крайней мере, один» для заголовка поля (возможно, принимая больше, если 12
на самом деле 1234567
) - и «по крайней мере, один» для длины, которая становится больше для более длинных сообщений.Группа получает 2 x заголовка поля, поэтому, если вы используете младшие номера полей, это будет 2 байта независимо от длины инкапсулированных данных (это может быть 5 МБ двоичных данных).
Отдельный прием,полезен для более сложных сценариев, но не как совместимый, является универсальным наследованием, то есть абстрактным базовым классом, который имеет ConcreteType<int>
, ConcreteType<string>
и т. д., перечисленные как подтипы - это, однако, занимает дополнительные 2 байта (как правило), так что это не такбережливое.
Удаляя еще на шаг дальше от основной спецификации, если вы действительно не можете сказать , какие типы вам нужно поддерживать, и вам не нужна совместимость- есть некоторая поддержка для включения (оптимизированной) информации о типе в данные;см. параметр DynamicType
на ProtoMember
- это занимает больше места, чем два других параметра.