정리
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using MessagePack.Formatters;
|
||||
using MessagePack.Internal;
|
||||
|
||||
namespace MessagePack.Resolvers
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a collection of formatters and resolvers acting as one.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This class is not thread-safe for mutations. It is thread-safe when not being written to.
|
||||
/// </remarks>
|
||||
public static class CompositeResolver
|
||||
{
|
||||
private static readonly ReadOnlyDictionary<Type, IMessagePackFormatter> EmptyFormattersByType = new ReadOnlyDictionary<Type, IMessagePackFormatter>(new Dictionary<Type, IMessagePackFormatter>());
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of an <see cref="IFormatterResolver"/> with the specified formatters and sub-resolvers.
|
||||
/// </summary>
|
||||
/// <param name="formatters">
|
||||
/// A list of instances of <see cref="IMessagePackFormatter{T}"/> to prefer (above the <paramref name="resolvers"/>).
|
||||
/// The formatters are searched in the order given, so if two formatters support serializing the same type, the first one is used.
|
||||
/// May not be null, but may be <see cref="Array.Empty{T}"/>.
|
||||
/// </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.
|
||||
/// May not be null, but may be <see cref="Array.Empty{T}"/>.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// An instance of <see cref="IFormatterResolver"/>.
|
||||
/// </returns>
|
||||
public static IFormatterResolver Create(IReadOnlyList<IMessagePackFormatter> formatters, IReadOnlyList<IFormatterResolver> resolvers)
|
||||
{
|
||||
if (formatters is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(formatters));
|
||||
}
|
||||
|
||||
if (resolvers is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(resolvers));
|
||||
}
|
||||
|
||||
// Make a copy of the resolvers list provided by the caller to guard against them changing it later.
|
||||
var immutableFormatters = formatters.ToArray();
|
||||
var immutableResolvers = resolvers.ToArray();
|
||||
|
||||
return new CachingResolver(immutableFormatters, immutableResolvers);
|
||||
}
|
||||
|
||||
public static IFormatterResolver Create(params IFormatterResolver[] resolvers) => Create(Array.Empty<IMessagePackFormatter>(), resolvers);
|
||||
|
||||
public static IFormatterResolver Create(params IMessagePackFormatter[] formatters) => Create(formatters, Array.Empty<IFormatterResolver>());
|
||||
|
||||
private class CachingResolver : IFormatterResolver
|
||||
{
|
||||
private readonly ThreadsafeTypeKeyHashTable<IMessagePackFormatter?> formattersCache = new();
|
||||
private readonly IMessagePackFormatter[] subFormatters;
|
||||
private readonly IFormatterResolver[] subResolvers;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CachingResolver"/> class.
|
||||
/// </summary>
|
||||
internal CachingResolver(IMessagePackFormatter[] subFormatters, IFormatterResolver[] subResolvers)
|
||||
{
|
||||
this.subFormatters = subFormatters ?? throw new ArgumentNullException(nameof(subFormatters));
|
||||
this.subResolvers = subResolvers ?? throw new ArgumentNullException(nameof(subResolvers));
|
||||
}
|
||||
|
||||
public IMessagePackFormatter<T>? GetFormatter<T>()
|
||||
{
|
||||
if (!this.formattersCache.TryGetValue(typeof(T), out IMessagePackFormatter? formatter))
|
||||
{
|
||||
foreach (var subFormatter in this.subFormatters)
|
||||
{
|
||||
if (subFormatter is IMessagePackFormatter<T>)
|
||||
{
|
||||
formatter = subFormatter;
|
||||
goto CACHE;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (IFormatterResolver resolver in this.subResolvers)
|
||||
{
|
||||
formatter = resolver.GetFormatter<T>();
|
||||
if (formatter != null)
|
||||
{
|
||||
goto CACHE;
|
||||
}
|
||||
}
|
||||
|
||||
// when not found, cache null.
|
||||
CACHE:
|
||||
this.formattersCache.TryAdd(typeof(T), formatter);
|
||||
}
|
||||
|
||||
return (IMessagePackFormatter<T>?)formatter;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user