Skip to content

Collections

Vladyslav Taranov edited this page Mar 12, 2016 · 10 revisions

Collection handling

Collection types use a special handling and can't have serializable members. You may want your type to be handled not as a collection:

[SerializableType(IgnoreListHandling = true)]
class NotACollection : IList<int>
{
    // ...
}

Or the same using code mapping:

RuntimeTypeModel model = TypeModel.Create();
model.Add(typeof(NotACollection), true).IgnoreListHandling = true;

Available formats

  • Enhanced - own format incompatible with Protocol Buffers.
  • Protobuf - Protocol Buffers format when all primitive types are packed.
  • ProtobufNotPacked - old Protocol Buffers format without packing support.

All of them are incompatible between each other (except that changing from ProtobufNotPacked to Protobuf is possible).

The default format is Enhanced but in compatibility mode it's replaced with Protobuf.

Enhanced format features

  • Nested collections support.
  • Multidimensional arrays support (in addition to single-dimensional).
  • Empty arrays are not treated the same as null and vice versa.
  • Collection subtype information is preserved.
  • Always packed for better output size, also applied to non-primitive types.
  • Supported referencing an array from inside itself.

Auxiliary mode

For not nested root collections without a contract attribute (SerializableType, DataContract, etc) the Auxiliary mode is used unless a collection type is explicitly registered with model.Add or by using serializable member of such collection type. You can disable this behavior by specifying model.AlwaysUseTypeRegistrationForCollections = true.

The purpose of this mode is to allow serialization of unknown collection types when an item type is registered. It may be useful for precompiled models where adding a new collection type is not possible.

Auxiliary serialization always uses GoogleNotPacked format.

Format specifying

You can specify desired format on a type using an attribute. In this example Persons will be serialized using Protobuf collection format:
[SerializableType(CollectionFormat = CollectionFormat.Protobuf)]
class PersonList : List<string>
{
 
}

[SerializableType]
class Foo
{
     [SerializableMember(1)]
     public PersonList Persons { get; set; }
}

Or using code mapping:

RuntimeTypeModel model = TypeModel.Create();
model.Add(typeof(PersonList), true).CollectionFormat = CollectionFormat.Protobuf;
The specified collection format may be overridden with a member attribute:
[SerializableType]
class Foo
{
     [SerializableMember(5, CollectionFormat = CollectionFormat.Enhanced)]
     public PersonList Persons { get; set; }
}

Or using code mapping:

model.Add(typeof(Foo), true)[5]
    .SetSettings(x => x.V.Collection.Format = CollectionFormat.Enhanced);
For collection members it may be overridden like this:
[SerializableType]
class Foo
{
     [SerializableMember(5)]
     [SerializableMemberNested(/* nested level: */ 1, CollectionFormat = CollectionFormat.Enhanced)]
     public List<PersonList> ListOfListOfPersons { get; set; }
}

Or using code mapping:

model.Add(typeof(Foo), true)[5]
    .SetSettings(x => x.V.Collection.Format = CollectionFormat.Enhanced,
         /* nested level: */ 1);
You may even specify different collection formats for member and nested level:
[SerializableType]
class Foo
{
     [SerializableMember(5, CollectionFormat = CollectionFormat.ProtobufNotPacked)] // List<PersonList>
     [SerializableMemberNested(/* nested level: */ 1, CollectionFormat = CollectionFormat.Enhanced)] // PersonList
     public List<PersonList> ListOfListOfPersons { get; set; }
}

Or using code mapping:

model.Add(typeof(Foo), true)[5]
    .SetSettings(x => x.V.Collection.Format = CollectionFormat.ProtobufNotPacked);
model.Add(typeof(Foo), true)[5]
    .SetSettings(x => x.V.Collection.Format = CollectionFormat.Enhanced,
         /* nested level: */ 1);

Legacy members

For members mapped with protobuf-net attributes:

IsPacked Proto compatibility mode Format
false / not specified false Inherited from a type of value / default
false / not specified true ProtobufNotPacked
true false Protobuf
true true Protobuf