diff --git a/src/Riok.Mapperly/Descriptors/MappingBodyBuilders/BuilderContext/MembersMappingStateBuilder.cs b/src/Riok.Mapperly/Descriptors/MappingBodyBuilders/BuilderContext/MembersMappingStateBuilder.cs
index 2cde682760..652fa2daef 100644
--- a/src/Riok.Mapperly/Descriptors/MappingBodyBuilders/BuilderContext/MembersMappingStateBuilder.cs
+++ b/src/Riok.Mapperly/Descriptors/MappingBodyBuilders/BuilderContext/MembersMappingStateBuilder.cs
@@ -30,7 +30,9 @@ public static MembersMappingState Build(MappingBuilderContext ctx)
unmappedSourceMemberNames.ExceptWith(ignoredSourceMemberNames);
targetMembers.RemoveRange(ignoredTargetMemberNames);
- var targetMemberCaseMapping = targetMembers.Keys.ToDictionary(x => x, x => x, StringComparer.OrdinalIgnoreCase);
+ var targetMemberCaseMapping = targetMembers
+ .Keys.GroupBy(x => x, StringComparer.OrdinalIgnoreCase)
+ .ToDictionary(x => x.Key, x => x.First(), StringComparer.OrdinalIgnoreCase);
var unmappedTargetMemberNames = targetMembers.Keys.ToHashSet();
return new MembersMappingState(
unmappedSourceMemberNames,
diff --git a/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyTest.cs b/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyTest.cs
index ced80bccd7..2949b8e7fa 100644
--- a/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyTest.cs
+++ b/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyTest.cs
@@ -435,6 +435,35 @@ public void UnmappedReadOnlyTargetPropertyShouldNotDiagnostic()
);
}
+ [Fact]
+ public Task PropertiesWithCaseInsensitiveEqualNamesShouldWork()
+ {
+ var source = TestSourceBuilder.Mapping(
+ "A",
+ "B",
+ "class A { public int Value { get; set; } }",
+ "class B { public int value { get; set; } public int Value { get; set; } }"
+ );
+
+ return TestHelper.VerifyGenerator(source);
+ }
+
+ [Fact]
+ public Task PropertyConfigurationShouldPreferExactCasing()
+ {
+ var source = TestSourceBuilder.MapperWithBodyAndTypes(
+ """
+ [MapProperty("Value", "value")]
+ [MapProperty("value", "Value")]
+ public partial B Map(A source);
+ """,
+ "class A { public int value { get; set; } public int Value { get; set; } }",
+ "class B { public int value { get; set; } public int Value { get; set; } }"
+ );
+
+ return TestHelper.VerifyGenerator(source);
+ }
+
[Fact]
public void ShouldIgnoreStaticProperty()
{
diff --git a/test/Riok.Mapperly.Tests/_snapshots/ObjectPropertyTest.PropertiesWithCaseInsensitiveEqualNamesShouldWork#Mapper.g.verified.cs b/test/Riok.Mapperly.Tests/_snapshots/ObjectPropertyTest.PropertiesWithCaseInsensitiveEqualNamesShouldWork#Mapper.g.verified.cs
new file mode 100644
index 0000000000..34a4a20c20
--- /dev/null
+++ b/test/Riok.Mapperly.Tests/_snapshots/ObjectPropertyTest.PropertiesWithCaseInsensitiveEqualNamesShouldWork#Mapper.g.verified.cs
@@ -0,0 +1,13 @@
+//HintName: Mapper.g.cs
+//
+#nullable enable
+public partial class Mapper
+{
+ [global::System.CodeDom.Compiler.GeneratedCode("Riok.Mapperly", "0.0.1.0")]
+ private partial global::B Map(global::A source)
+ {
+ var target = new global::B();
+ target.Value = source.Value;
+ return target;
+ }
+}
\ No newline at end of file
diff --git a/test/Riok.Mapperly.Tests/_snapshots/ObjectPropertyTest.PropertiesWithCaseInsensitiveEqualNamesShouldWork.verified.txt b/test/Riok.Mapperly.Tests/_snapshots/ObjectPropertyTest.PropertiesWithCaseInsensitiveEqualNamesShouldWork.verified.txt
new file mode 100644
index 0000000000..6cc7952524
--- /dev/null
+++ b/test/Riok.Mapperly.Tests/_snapshots/ObjectPropertyTest.PropertiesWithCaseInsensitiveEqualNamesShouldWork.verified.txt
@@ -0,0 +1,14 @@
+{
+ Diagnostics: [
+ {
+ Id: RMG012,
+ Title: Source member was not found for target member,
+ Severity: Info,
+ WarningLevel: 1,
+ Location: : (11,4)-(11,36),
+ MessageFormat: The member {0} on the mapping target type {1} was not found on the mapping source type {2},
+ Message: The member value on the mapping target type B was not found on the mapping source type A,
+ Category: Mapper
+ }
+ ]
+}
\ No newline at end of file
diff --git a/test/Riok.Mapperly.Tests/_snapshots/ObjectPropertyTest.PropertyConfigurationShouldPreferExactCasing#Mapper.g.verified.cs b/test/Riok.Mapperly.Tests/_snapshots/ObjectPropertyTest.PropertyConfigurationShouldPreferExactCasing#Mapper.g.verified.cs
new file mode 100644
index 0000000000..e66ea73aac
--- /dev/null
+++ b/test/Riok.Mapperly.Tests/_snapshots/ObjectPropertyTest.PropertyConfigurationShouldPreferExactCasing#Mapper.g.verified.cs
@@ -0,0 +1,14 @@
+//HintName: Mapper.g.cs
+//
+#nullable enable
+public partial class Mapper
+{
+ [global::System.CodeDom.Compiler.GeneratedCode("Riok.Mapperly", "0.0.1.0")]
+ public partial global::B Map(global::A source)
+ {
+ var target = new global::B();
+ target.value = source.Value;
+ target.Value = source.value;
+ return target;
+ }
+}
\ No newline at end of file