150 lines
6.0 KiB
C#
150 lines
6.0 KiB
C#
// Copyright (c) All contributors. All rights reserved.
|
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using MessagePack.Formatters;
|
|
|
|
namespace MessagePack.Resolvers
|
|
{
|
|
/// <summary>
|
|
/// Singleton version of CompositeResolver, which be able to register a collection of formatters and resolvers to a single instance.
|
|
/// </summary>
|
|
public class StaticCompositeResolver : IFormatterResolver
|
|
{
|
|
public static readonly StaticCompositeResolver Instance = new StaticCompositeResolver();
|
|
|
|
private bool freezed;
|
|
private IReadOnlyList<IMessagePackFormatter> formatters;
|
|
private IReadOnlyList<IFormatterResolver> resolvers;
|
|
|
|
private StaticCompositeResolver()
|
|
{
|
|
formatters = Array.Empty<IMessagePackFormatter>();
|
|
resolvers = Array.Empty<IFormatterResolver>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a singleton instance with the specified formatters.
|
|
/// This method can only call before use StaticCompositeResolver.Instance.GetFormatter.
|
|
/// If call twice in the Register methods, registered formatters and resolvers will be overridden.
|
|
/// </summary>
|
|
/// <param name="formatters">
|
|
/// A list of instances of <see cref="IMessagePackFormatter{T}"/>.
|
|
/// The formatters are searched in the order given, so if two formatters support serializing the same type, the first one is used.
|
|
/// </param>
|
|
public void Register(params IMessagePackFormatter[] formatters)
|
|
{
|
|
if (this.freezed)
|
|
{
|
|
throw new InvalidOperationException("Register must call on startup(before use GetFormatter<T>).");
|
|
}
|
|
|
|
if (this.formatters is null)
|
|
{
|
|
throw new ArgumentNullException(nameof(formatters));
|
|
}
|
|
|
|
this.formatters = formatters;
|
|
this.resolvers = Array.Empty<IFormatterResolver>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a singleton instance with the specified formatters and sub-resolvers.
|
|
/// This method can only call before use StaticCompositeResolver.Instance.GetFormatter.
|
|
/// If call twice in the Register methods, registered formatters and resolvers will be overridden.
|
|
/// </summary>
|
|
/// <param name="resolvers">
|
|
/// A list of resolvers to use for serializing types.
|
|
/// The resolvers are searched in the order given, so if two resolvers support serializing the same type, the first one is used.
|
|
/// </param>
|
|
public void Register(params IFormatterResolver[] resolvers)
|
|
{
|
|
if (this.freezed)
|
|
{
|
|
throw new InvalidOperationException("Register must call on startup(before use GetFormatter<T>).");
|
|
}
|
|
|
|
if (resolvers is null)
|
|
{
|
|
throw new ArgumentNullException(nameof(resolvers));
|
|
}
|
|
|
|
this.formatters = Array.Empty<IMessagePackFormatter>();
|
|
this.resolvers = resolvers;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a singleton instance with the specified formatters and sub-resolvers.
|
|
/// This method can only call before use StaticCompositeResolver.Instance.GetFormatter.
|
|
/// If call twice in the Register methods, registered formatters and resolvers will be overridden.
|
|
/// </summary>
|
|
/// <param name="formatters">
|
|
/// A list of instances of <see cref="IMessagePackFormatter{T}"/>.
|
|
/// The formatters are searched in the order given, so if two formatters support serializing the same type, the first one is used.
|
|
/// </param>
|
|
/// <param name="resolvers">
|
|
/// A list of resolvers to use for serializing types for which <paramref name="formatters"/> does not include a formatter.
|
|
/// The resolvers are searched in the order given, so if two resolvers support serializing the same type, the first one is used.
|
|
/// </param>
|
|
public void Register(IReadOnlyList<IMessagePackFormatter> formatters, IReadOnlyList<IFormatterResolver> resolvers)
|
|
{
|
|
if (this.freezed)
|
|
{
|
|
throw new InvalidOperationException("Register must call on startup(before use GetFormatter<T>).");
|
|
}
|
|
|
|
if (formatters is null)
|
|
{
|
|
throw new ArgumentNullException(nameof(formatters));
|
|
}
|
|
|
|
if (resolvers is null)
|
|
{
|
|
throw new ArgumentNullException(nameof(resolvers));
|
|
}
|
|
|
|
this.formatters = formatters;
|
|
this.resolvers = resolvers;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets an <see cref="IMessagePackFormatter{T}"/> instance that can serialize or deserialize some type <typeparamref name="T"/>.
|
|
/// </summary>
|
|
/// <typeparam name="T">The type of value to be serialized or deserialized.</typeparam>
|
|
/// <returns>A formatter, if this resolver supplies one for type <typeparamref name="T"/>; otherwise <c>null</c>.</returns>
|
|
public IMessagePackFormatter<T> GetFormatter<T>()
|
|
{
|
|
return Cache<T>.Formatter;
|
|
}
|
|
|
|
private static class Cache<T>
|
|
{
|
|
public static readonly IMessagePackFormatter<T> Formatter;
|
|
|
|
static Cache()
|
|
{
|
|
Instance.freezed = true;
|
|
foreach (var item in Instance.formatters)
|
|
{
|
|
if (item is IMessagePackFormatter<T> f)
|
|
{
|
|
Formatter = f;
|
|
return;
|
|
}
|
|
}
|
|
|
|
foreach (var item in Instance.resolvers)
|
|
{
|
|
var f = item.GetFormatter<T>();
|
|
if (f != null)
|
|
{
|
|
Formatter = f;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|