Skip to content

Member Formats

Vladyslav Taranov edited this page Mar 25, 2022 · 21 revisions

There are two possible formats:

  1. Compact - plain Google Protocol Buffers format without null support and reference tracking.
  2. Enhanced - not compatible with Compact, reading is compatible between different enhanced write modes:
  • MinimalEnhancement - has null support but still can be applied to non-nullable types.
  • Reference - adds reference tracking, includes MinimalEnhancement.
  • LateReference - indicates that the value should not be traversed recursively, includes Reference.

Format specifying

You can specify desired mode on a type using an attribute. In this example Person will be serialized with null support:
[SerializableType(ValueFormat.MinimalEnhancement)]
class Person
{
 
}

[SerializableType]
class Foo
{
     [SerializableMember(1)]
     public Person PersonData { get; set; }
}

Or using code mapping:

RuntimeTypeModel model = TypeModel.Create();
model.Add(typeof(Person), true).DefaultFormat = ValueFormat.MinimalEnhancement;
The specified mode may be overridden with a member attribute:
[SerializableType]
class Foo
{
     [SerializableMember(5, ValueFormat.Reference)]
     public Person PersonData { get; set; }
}

Or using code mapping:

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

Or using code mapping:

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

Defaults

When a mode is not specified neither on a type nor on a member it's determined automatically:

Type Default mode
class Reference
nullable? MinimalEnhancement
struct/enum Compact

Legacy attributes

Types mapped with [ProtoContract] attributes have special rules applied:

AsReferenceDefault Type Mode
true any Reference
false / not specified class MinimalEnhancement
false / not specified nullable? MinimalEnhancement
false / not specified struct/enum Compact

Members mapped with [ProtoMember] attributes (and "partial") have special rules applied:

AsReference Final mode
true Reference
false From the table above
not specified From inherited type settings or (if not specified) from the table above

For collection members item specified settings are usually copied from [ProtoMember] attribute (in a state before applying inherited type settings).

LateReference mode

If you receive Recursion depth exceeded safe limit exception LateReference mode may help you.

This mode changes reference tracking behavior to not use deep traversal ("to not go inside member recursively") but it has to write additional data and therefore it's slower. Use it only on concrete members which should not be traversed recursively like linked list nodes.

An example:

    [SerializableType]
    public class Node
    {
        [SerializableMember(1, ValueFormat.LateReference)]
        public Node Next { get; set; }

        [SerializableMember(2, ValueFormat.LateReference)]
        public Node Prev { get; set; }
        
        [SerializableMember(3)]
        public int Value { get; set; }
    }

In this mode you can't override any type settings like CollectionFormat or specify any member-specific settings like WriteAsDynamicType. The same rule is applied to nested levels (collection items). LateReference value is always written using type settings only without any customization.