From e9e8e2b0d2625e0247233e0355fee583817ddecf Mon Sep 17 00:00:00 2001 From: Timothy Makkison Date: Fri, 15 Sep 2023 11:33:18 +0100 Subject: [PATCH] feat: use .Net 8 ToDictionary --- .../DictionaryMappingBuilder.cs | 37 ++++++++++++++++ .../Mapping/DictionaryTest.cs | 44 ++----------------- 2 files changed, 41 insertions(+), 40 deletions(-) diff --git a/src/Riok.Mapperly/Descriptors/MappingBuilders/DictionaryMappingBuilder.cs b/src/Riok.Mapperly/Descriptors/MappingBuilders/DictionaryMappingBuilder.cs index c12866fbb4..dcb2f33c1e 100644 --- a/src/Riok.Mapperly/Descriptors/MappingBuilders/DictionaryMappingBuilder.cs +++ b/src/Riok.Mapperly/Descriptors/MappingBuilders/DictionaryMappingBuilder.cs @@ -13,6 +13,8 @@ public static class DictionaryMappingBuilder { private const string SetterIndexerPropertyName = "set_Item"; + private const string ToDictionaryMethodName = "ToDictionary"; + private const string ToDictionaryMethodFullName = "global::System.Collections.Generic.Enumerable.ToDictionary"; private const string ToImmutableDictionaryMethodName = "global::System.Collections.Immutable.ImmutableDictionary.ToImmutableDictionary"; private const string ToImmutableSortedDictionaryMethodName = "global::System.Collections.Immutable.ImmutableSortedDictionary.ToImmutableSortedDictionary"; @@ -37,6 +39,9 @@ or CollectionType.IDictionary or CollectionType.IReadOnlyDictionary ) { + if (TryGetToDictionary(ctx, keyMapping, valueMapping) is { } toDictionary) + return toDictionary; + var targetDictionarySymbol = ctx.Types.Get(typeof(Dictionary<,>)).Construct(keyMapping.TargetType, valueMapping.TargetType); ctx.ObjectFactories.TryFindObjectFactory(ctx.Source, ctx.Target, out var dictionaryObjectFactory); return new ForEachSetDictionaryMapping( @@ -135,6 +140,38 @@ private static (INewInstanceMapping, INewInstanceMapping)? BuildKeyValueMapping( return (keyMapping, valueMapping); } + private static INewInstanceMapping? TryGetToDictionary( + MappingBuilderContext ctx, + INewInstanceMapping keyMapping, + INewInstanceMapping valueMapping + ) + { + if (!keyMapping.IsSynthetic || !valueMapping.IsSynthetic || keyMapping.TargetType.IsNullable()) + return null; + + // use .NET 8 method .ToDictionary() if value and key mapping is synthetic + var enumerableType = ctx.Types.Get(typeof(IEnumerable<>)); + var dictionaryType = ctx.Types.Get(typeof(Dictionary<,>)); + + var toDictionaryMethod = ctx.Types + .Get(typeof(Enumerable)) + .GetMembers(ToDictionaryMethodName) + .OfType() + .FirstOrDefault( + x => + x is { IsStatic: true, Parameters.Length: 1, IsGenericMethod: true } + && SymbolEqualityComparer.Default.Equals(x.ReturnType.OriginalDefinition, dictionaryType) + && SymbolEqualityComparer.Default.Equals(((INamedTypeSymbol)x.Parameters[0].Type).ConstructedFrom, enumerableType) + ); + + if (toDictionaryMethod != null) + { + return new LinqDictionaryMapping(ctx.Source, ctx.Target, ToDictionaryMethodFullName, keyMapping, valueMapping); + } + + return null; + } + private static INamedTypeSymbol? GetExplicitIndexer(MappingBuilderContext ctx) { if ( diff --git a/test/Riok.Mapperly.Tests/Mapping/DictionaryTest.cs b/test/Riok.Mapperly.Tests/Mapping/DictionaryTest.cs index a9adfc042f..549f59e302 100644 --- a/test/Riok.Mapperly.Tests/Mapping/DictionaryTest.cs +++ b/test/Riok.Mapperly.Tests/Mapping/DictionaryTest.cs @@ -24,16 +24,7 @@ public void DictionaryToSameDictionaryDeepCloning() TestHelper .GenerateMapper(source) .Should() - .HaveSingleMethodBody( - """ - var target = new global::System.Collections.Generic.Dictionary(source.Count); - foreach (var item in source) - { - target[item.Key] = item.Value; - } - return target; - """ - ); + .HaveSingleMethodBody("return global::System.Collections.Generic.Enumerable.ToDictionary(source);"); } [Fact] @@ -126,16 +117,7 @@ public void KeyValueEnumerableToIDictionary() TestHelper .GenerateMapper(source) .Should() - .HaveSingleMethodBody( - """ - var target = new global::System.Collections.Generic.Dictionary(); - foreach (var item in source) - { - target[item.Key] = item.Value; - } - return target; - """ - ); + .HaveSingleMethodBody("return global::System.Collections.Generic.Enumerable.ToDictionary(source);"); } [Fact] @@ -145,16 +127,7 @@ public void CustomDictionaryToIDictionary() TestHelper .GenerateMapper(source) .Should() - .HaveSingleMethodBody( - """ - var target = new global::System.Collections.Generic.Dictionary(source.Count); - foreach (var item in source) - { - target[item.Key] = item.Value; - } - return target; - """ - ); + .HaveSingleMethodBody("return global::System.Collections.Generic.Enumerable.ToDictionary(source);"); } [Fact] @@ -164,16 +137,7 @@ public void CustomKeyValueListToIDictionary() TestHelper .GenerateMapper(source) .Should() - .HaveSingleMethodBody( - """ - var target = new global::System.Collections.Generic.Dictionary(source.Count); - foreach (var item in source) - { - target[item.Key] = item.Value; - } - return target; - """ - ); + .HaveSingleMethodBody("return global::System.Collections.Generic.Enumerable.ToDictionary(source);"); } [Fact]