diff --git a/src/Riok.Mapperly/Descriptors/MappingBuilders/DictionaryMappingBuilder.cs b/src/Riok.Mapperly/Descriptors/MappingBuilders/DictionaryMappingBuilder.cs index c12866fbb4..ef8a90a5cf 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 ToDictionaryName = "ToDictionary"; + private const string ToDictionaryMethodName = "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,32 @@ or CollectionType.IDictionary or CollectionType.IReadOnlyDictionary ) { + // use .NET 8 method .ToDictionary() if value and key mapping is synthetic + if (keyMapping.IsSynthetic && valueMapping.IsSynthetic && !keyMapping.TargetType.IsNullable()) + { + var enumerableType = ctx.Types.Get(typeof(IEnumerable<>)); + var dictionaryType = ctx.Types.Get(typeof(Dictionary<,>)); + + var toDictionaryMethod = ctx.Types + .Get(typeof(Enumerable)) + .GetMembers(ToDictionaryName) + .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, ToDictionaryMethodName, keyMapping, valueMapping); + } + } + 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( 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]