Skip to content
Marek Fišera edited this page Jan 25, 2018 · 4 revisions

Formatters providers abstractions for serializing (use ISerializer) and deserializing (use IDeserializer) objects, where both operation are needed, use IFormatter. There are packages for processing objects to and from JSON (base on Newtonsoft.Json) and XML. The contracts are asynchronous and takes/provides System.IO.Stream.

Composite

Beside these simple wrapper implementations there is implementation called Composite which supports versioned processing. Any object can evolve from initial version to some bigger (or different) version, but serializer and deserializer will support loading and storing older versions from current type version.

For serializing and deserializing objects using composite formatter, you can choose from two options. The first is to implement ICompositeModel and load and save object state manually. The second one is to use one of the model definition providers and let the infrastructure serialize and deserialize your types. This option is based on assigning properties and constructor to a version of the type. A current version of the object is determined from specially marked property. You can describe such model in two ways, using fluent interface or attributes (in demos here we will use attributes).

The simplest composite model can be:

public class SingleModel
{
    public string FullName { get; private set; }

    public SingleModel(string fullName)
    {
        FullName = fullName;
    }
}

Here you have one version which is created by constructor with fullName and which has single property FullName. This mode is based on conventions where property count must match constructor parameter count. Properties are matched to constructor parameters by name, so these names must (case-insensitively) match.

/// <summary>
/// Class version support, but currently has only a single version.
/// Constructor is explicitly marked.
/// </summary>
public class SingleVersion
{
    [CompositeVersion]
    public int Version { get; private set; }

    public string FullName { get; private set; }

    /// <summary>
    /// This should not be used by composite.
    /// </summary>
    public SingleVersion()
    { }

    [CompositeConstructor]
    public SingleVersion(string fullName)
    {
        FullName = fullName;
    }
}

This model still has single version, but explicitly marks constructor that should be used and also defines property that determines current version.

The attribute [CompositeConstructor] is required because the type defines more than one constructor. Properties are still matched by name to contructor parameters.

/// <summary>
/// Class with two versions.
/// Constructors are marked, but properties for version 1 are by convension.
/// </summary>
public class TwoVersionWithFirstImplied
{
    [CompositeVersion]
    public int Version { get; set; }

    public string FullName { get; private set; }

    [CompositeProperty(0, Version = 2)]
    public string FirstName { get; private set; }

    [CompositeProperty(1, Version = 2)]
    public string LastName { get; private set; }

    [CompositeConstructor]
    public TwoVersionWithFirstImplied(string fullName)
    {
        FullName = fullName;
    }

    [CompositeConstructor(Version = 2)]
    public TwoVersionWithFirstImplied(string param1, string param2)
    {
        FirstName = param1;
        LastName = param2;
    }
}

This model has two versions. The first implied from the constructor marked with [CompositeConstructor]. The model builders looks properties from constructor parameters. The names must match (except for the casing). The second version is fully explicitly defined. Property names doesn't match with constructor parameters, so explicit order must be defined (use [CompositeProperty(0, Version = 2)] and [CompositeProperty(1, Version = 2)]).

Clone this wiki locally