Table of Contents

Class MsgPackArrayContractAttribute

Namespace
ShapeShift.MsgPack
Assembly
ShapeShift.MsgPack.dll

Declares that a type is serialized as a MessagePack array whose elements are identified by position (see MsgPackKeyAttribute) instead of as a map keyed by property name.

[AttributeUsage(AttributeTargets.Class|AttributeTargets.Struct|AttributeTargets.Interface, AllowMultiple = false, Inherited = false)]
public sealed class MsgPackArrayContractAttribute : Attribute
Inheritance
MsgPackArrayContractAttribute
Inherited Members

Examples

var serializer = new MsgPackSerializer();

// A map contract (the default) writes property names, so it tolerates members being added,
// removed, and renamed. A positional contract writes only values, located by the permanent
// positions [MsgPackKey] assigns, which is dramatically more compact for small records.
byte[] asMap = serializer.Serialize(new MapMeasurement("t1", 21.5, 1013.2));
byte[] asArray = serializer.Serialize(new Measurement("t1", 21.5, 1013.2));

Measurement? roundTripped = serializer.Deserialize<Measurement>(asArray);

Remarks

Map contracts are the ShapeShift default because they are the most version tolerant. Positional contracts trade that tolerance for compactness: property names never appear on the wire, so a small object can shrink dramatically. Apply this attribute only when both ends of a payload are versioned together, or when the versioning rules below are followed strictly.

Versioning rules.

  1. Every serializable member must declare a MsgPackKeyAttribute. There is no implicit ordering.
  2. A key, once shipped, belongs to that member forever. Retire keys; never reuse or reorder them.
  3. New members take keys above every key already in use.
  4. A retired key becomes a hole. Holes are written as a MessagePack nil placeholder whenever a later position is still written, and readers skip whatever they find at a position they no longer recognize.
  5. A reader accepts an array that is shorter than its own contract (members at the missing positions keep their default values, subject to required-member validation) and an array that is longer (the surplus elements are skipped). That is what makes appending a member backward and forward compatible.

Omitted values. A MessagePack array has no way to say that an interior element is absent as opposed to null, so a positional contract declines SerializeDefaultValuesPolicy omission for interior positions: those members are always written, at their real values, even when that value is the default. Omission is honored only for the tail of the array, where a shorter array is an unambiguous statement that the remaining positions were not written. Required members are never elided, because a reader could not reconstruct the object without them.

Unsupported combinations. A positional contract cannot carry an extension-data member (ShapeShiftExtensionDataAttribute): unknown positions have no names to retain them under. Applying both raises a ShapeShiftSerializationException when the converter is built.