Skip to content

Commit

Permalink
Refined converter API (#2593)
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelstaib committed Nov 16, 2020
1 parent ae265d4 commit 903d61a
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 22 deletions.
31 changes: 15 additions & 16 deletions src/HotChocolate/Core/src/Types/Utilities/DefaultTypeConverter.cs
Expand Up @@ -8,13 +8,10 @@

namespace HotChocolate.Utilities
{
public partial class DefaultTypeConverter
: ITypeConverter
public partial class DefaultTypeConverter : ITypeConverter
{
private readonly ConcurrentDictionary<Type, ConcurrentDictionary<Type, ChangeType>> _converters =
new ConcurrentDictionary<Type, ConcurrentDictionary<Type, ChangeType>>();
private readonly List<IChangeTypeProvider> _changeTypeProvider =
new List<IChangeTypeProvider>();
private readonly ConcurrentDictionary<(Type, Type), ChangeType> _converters = new();
private readonly List<IChangeTypeProvider> _changeTypeProvider = new();

public DefaultTypeConverter(IEnumerable<IChangeTypeProvider>? providers = null)
{
Expand Down Expand Up @@ -107,11 +104,16 @@ private bool TryConvertInternal(Type from, Type to, object source, out object? c
Type to,
[NotNullWhen(true)] out ChangeType? converter)
{
if (TryGetConverter(from, to, out converter)
|| TryCreateConverterFromFactory(from, to, out converter))
if (TryGetConverter(from, to, out converter))
{
return true;
}

if (TryCreateConverterFromFactory(from, to, out converter))
{
return true;
}

return false;
}

Expand All @@ -127,6 +129,7 @@ private bool TryConvertInternal(Type from, Type to, object source, out object? c
if (provider.TryCreateConverter(
source, target, TryGetOrCreateConverter, out converter))
{
_converters.TryAdd((source, target), converter);
return true;
}
}
Expand All @@ -143,16 +146,12 @@ private bool TryConvertInternal(Type from, Type to, object source, out object? c
{
if (source == target || target == typeof(object))
{
converter = source => source;
converter = s => s;
return true;
}

if (_converters.TryGetValue(source,
out ConcurrentDictionary<Type, ChangeType>? toLookUp)
&& toLookUp.TryGetValue(target,
out ChangeType? changeType))
if (_converters.TryGetValue((source, target), out converter))
{
converter = changeType;
return true;
}

Expand All @@ -173,7 +172,7 @@ private bool TryConvertInternal(Type from, Type to, object source, out object? c
return converter((TSource)input);
}));

public static DefaultTypeConverter Default { get; } = new DefaultTypeConverter();
public static DefaultTypeConverter Default { get; } = new();

private sealed class DelegateTypeConverter : IChangeTypeProvider
{
Expand Down Expand Up @@ -205,4 +204,4 @@ public DelegateTypeConverter(Type source, Type target, ChangeType converter)
}
}
}
}
}
Expand Up @@ -6,9 +6,9 @@ namespace HotChocolate.Utilities
internal sealed class EnumTypeConverter : IChangeTypeProvider
{
public bool TryCreateConverter(
Type source,
Type target,
ChangeTypeProvider root,
Type source,
Type target,
ChangeTypeProvider root,
[NotNullWhen(true)] out ChangeType converter)
{
if (source == typeof(string) && target.IsEnum)
Expand All @@ -19,7 +19,7 @@ internal sealed class EnumTypeConverter : IChangeTypeProvider

if (source.IsEnum && target == typeof(string))
{
converter = input => input.ToString();
converter = input => input?.ToString();
return true;
}

Expand Down
32 changes: 30 additions & 2 deletions src/HotChocolate/Core/src/Types/Utilities/IChangeTypeProvider.cs
Expand Up @@ -5,11 +5,39 @@

namespace HotChocolate.Utilities
{
/// <summary>
/// A <see cref="IChangeTypeProvider" /> is used by the type converter to create new converter.
/// Each <see cref="IChangeTypeProvider" /> can provide one ore multiple value converters.
/// </summary>
public interface IChangeTypeProvider
{
/// <summary>
/// Tries to create a converter that can convert a value that is of the
/// type <paramref name="source"/> to a value of the type <paramref name="target"/>.
/// If this type provider can only handle parts of the conversion it can refer back to the
/// root converter to ask other <see cref="IChangeTypeProvider"/> to provide the rest of
/// the type conversion.
/// </summary>
/// <param name="source">
/// The source type.
/// </param>
/// <param name="target">
/// The traget type.
/// </param>
/// <param name="root">
/// The root change type provider that has access to
/// all registered <see cref="IChangeTypeProvider"/>.
/// </param>
/// <param name="converter">
/// The converter that was produced by this instance.
/// </param>
/// <returns>
/// Returns a boolean indicating if this <see cref="IChangeTypeProvider"/> was able to
/// create a type converter.
/// </returns>
bool TryCreateConverter(
Type source,
Type target,
Type source,
Type target,
ChangeTypeProvider root,
[NotNullWhen(true)]out ChangeType? converter);
}
Expand Down

0 comments on commit 903d61a

Please sign in to comment.