Table of Contents

Interface IMessagePackConverterFactory

Namespace
Nerdbank.MessagePack
Assembly
Nerdbank.MessagePack.dll

A factory for MessagePackConverter<T> objects of arbitrary types.

public interface IMessagePackConverterFactory

Examples

A non-generic implementation of this interface is preferred when possible.

internal class NonGenericCustomConverterFactory : IMessagePackConverterFactory
{
    // special purpose factory knows exactly what it supports. No generic type parameter needed.
    public MessagePackConverter? CreateConverter(Type type, ITypeShape? shape, in ConverterContext context)
        => type == typeof(List<Guid>) ? new WrapInArrayConverter<List<Guid>>() : null;
}

When a generic context is required, implement ITypeShapeFunc on the same class and invoke into it after appropriate type checks.

internal class GenericCustomConverterFactory : IMessagePackConverterFactory, ITypeShapeFunc
{
    // perform type check, then defer to generic method.
    public MessagePackConverter? CreateConverter(Type type, ITypeShape? shape, in ConverterContext context)
        => shape?.Type == typeof(int) ? this.Invoke(shape) : null;

    // type check is already done, just create the converter.
    object? ITypeShapeFunc.Invoke<T>(ITypeShape<T> typeShape, object? state)
        => new WrapInArrayConverter<T>();
}

When generic type parameters are required for sub-elements of the type to be converted (e.g. the element type of a collection), you can leverage a TypeShapeVisitor implementation to obtain the generic type parameters.

internal class VisitorCustomConverterFactory : IMessagePackConverterFactory
{
    // perform type check, then defer to generic method.
    public MessagePackConverter? CreateConverter(Type type, ITypeShape? shape, in ConverterContext context)
        => shape is IEnumerableTypeShape enumShape && enumShape.Type.GetGenericTypeDefinition() == typeof(List<>) ?
            (MessagePackConverter?)shape.Accept(Visitor.Instance) : null;

    private class Visitor : TypeShapeVisitor
    {
        internal static readonly Visitor Instance = new();

        public override object? VisitEnumerable<TEnumerable, TElement>(IEnumerableTypeShape<TEnumerable, TElement> enumerableShape, object? state = null)
            => new CustomListConverter<TElement>();
    }
}

Methods

CreateConverter(Type, ITypeShape?, in ConverterContext)

Creates a converter for the given type if this factory is capable of it.

MessagePackConverter? CreateConverter(Type type, ITypeShape? shape, in ConverterContext context)

Parameters

type Type

The type to be serialized.

shape ITypeShape

The shape of the type to be serialized, if available. The shape will typically be available. The only known exception is when the type has a PolyType marshaler defined.

context ConverterContext

The context in which this factory is being invoked. Provides access to other converters that may be required by the requested converter.

Returns

MessagePackConverter

The converter for the data type, or null.

Remarks

Implementations that require a generic type parameter for the type to be converted should also implement ITypeShapeFunc with an Invoke<T>(ITypeShape<T>, object) method that creates the converter. The implementation of this method should perform any type checks necessary to determine whether this factory applies to the given shape, and if so, call Invoke<T>(T, ITypeShape, object?) to forward the call to the generic Invoke<T>(ITypeShape<T>, object) method defined on that same class.