diff --git a/src/Riok.Mapperly/Descriptors/ObjectFactories/ObjectFactoryCollection.cs b/src/Riok.Mapperly/Descriptors/ObjectFactories/ObjectFactoryCollection.cs index f3effdbf8c..a863645abe 100644 --- a/src/Riok.Mapperly/Descriptors/ObjectFactories/ObjectFactoryCollection.cs +++ b/src/Riok.Mapperly/Descriptors/ObjectFactories/ObjectFactoryCollection.cs @@ -5,18 +5,19 @@ namespace Riok.Mapperly.Descriptors.ObjectFactories; public class ObjectFactoryCollection(IReadOnlyCollection objectFactories) { - private readonly Dictionary _concreteObjectFactories = new(SymbolEqualityComparer.IncludeNullability); + private readonly Dictionary _concreteObjectFactories = new(); public bool TryFindObjectFactory(ITypeSymbol sourceType, ITypeSymbol targetType, [NotNullWhen(true)] out ObjectFactory? objectFactory) { - if (_concreteObjectFactories.TryGetValue(targetType, out objectFactory)) + var key = new TypeMappingKey(sourceType, targetType); + if (_concreteObjectFactories.TryGetValue(key, out objectFactory)) return true; objectFactory = objectFactories.FirstOrDefault(f => f.CanCreateType(sourceType, targetType)); if (objectFactory == null) return false; - _concreteObjectFactories[targetType] = objectFactory; + _concreteObjectFactories[key] = objectFactory; return true; } } diff --git a/test/Riok.Mapperly.Tests/Mapping/ObjectFactoryTest.cs b/test/Riok.Mapperly.Tests/Mapping/ObjectFactoryTest.cs index effc47c768..27ad8d9d09 100644 --- a/test/Riok.Mapperly.Tests/Mapping/ObjectFactoryTest.cs +++ b/test/Riok.Mapperly.Tests/Mapping/ObjectFactoryTest.cs @@ -205,10 +205,19 @@ public void ShouldUseGenericSourceObjectFactory() public void ShouldUseFirstMatchingObjectFactory() { var source = TestSourceBuilder.MapperWithBodyAndTypes( - "[ObjectFactory] A CreateA() => new A();" - + "[ObjectFactory] B CreateB() => new B();" - + "[ObjectFactory] T Create() where T : new() => new T();" - + "partial B Map(A a);", + """ + [ObjectFactory] + A CreateA() => new A(); + + [ObjectFactory] + B CreateB() => new B(); + + [ObjectFactory] + T Create() where T : new() + => new T(); + + partial B Map(A a); + """, "class A { public string StringValue { get; set; } }", "class B { public string StringValue { get; set; } }" ); @@ -372,6 +381,46 @@ public void ShouldUseGenericObjectFactoryAndThrowIfNoParameterlessCtor() ); } + [Fact] + public void MultipleObjectFactoriesMultipleMappingsShouldUseCorrect() + { + var source = TestSourceBuilder.MapperWithBodyAndTypes( + """ + [ObjectFactory] + private C CreateCFromA(A source) + => new C(); + + [ObjectFactory] + private C CreateCFromB(B source) + => new C(); + + partial C MapA(A source); + partial C MapB(B source); + """, + "record A;", + "record B;", + "record C;" + ); + + TestHelper + .GenerateMapper(source) + .Should() + .HaveMethodBody( + "MapA", + """ + var target = CreateCFromA(source); + return target; + """ + ) + .HaveMethodBody( + "MapB", + """ + var target = CreateCFromB(source); + return target; + """ + ); + } + [Fact] public void ShouldUseObjectFactoryWithRecursiveTypeParameter() {