ZK_Framework/Assets/Plugins/MessagePack/Resolvers/StaticCompositeResolver.cs

150 lines
6.0 KiB
C#
Raw Normal View History

// 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;
}
}
}
}
}
}