@@ -74,8 +74,16 @@ public ConstructorInfo FindConstructor(string[] names, Type[] types)
7474 int i = 0 ;
7575 for ( ; i < ctorParameters . Length ; i ++ )
7676 {
77- if ( ! string . Equals ( ctorParameters [ i ] . Name , names [ i ] , StringComparison . OrdinalIgnoreCase ) )
77+ if ( EqualsCI ( ctorParameters [ i ] . Name , names [ i ] ) )
78+ { } // exact match
79+ else if ( MatchNamesWithUnderscores && EqualsCIU ( ctorParameters [ i ] . Name , names [ i ] ) )
80+ { } // match after applying underscores
81+ else
82+ {
83+ // not a name match
7884 break ;
85+ }
86+
7987 if ( types [ i ] == typeof ( byte [ ] ) && ctorParameters [ i ] . ParameterType . FullName == SqlMapper . LinqBinary )
8088 continue ;
8189 var unboxedType = Nullable . GetUnderlyingType ( ctorParameters [ i ] . ParameterType ) ?? ctorParameters [ i ] . ParameterType ;
@@ -119,9 +127,8 @@ public ConstructorInfo FindExplicitConstructor()
119127 /// <returns>Mapping implementation</returns>
120128 public SqlMapper . IMemberMap GetConstructorParameter ( ConstructorInfo constructor , string columnName )
121129 {
122- var parameters = constructor . GetParameters ( ) ;
123-
124- return new SimpleMemberMap ( columnName , parameters . FirstOrDefault ( p => string . Equals ( p . Name , columnName , StringComparison . OrdinalIgnoreCase ) ) ) ;
130+ ParameterInfo param = MatchFirstOrDefault ( constructor . GetParameters ( ) , columnName , static p => p . Name ) ;
131+ return new SimpleMemberMap ( columnName , param ) ;
125132 }
126133
127134 /// <summary>
@@ -131,14 +138,7 @@ public SqlMapper.IMemberMap GetConstructorParameter(ConstructorInfo constructor,
131138 /// <returns>Mapping implementation</returns>
132139 public SqlMapper . IMemberMap GetMember ( string columnName )
133140 {
134- var property = Properties . Find ( p => string . Equals ( p . Name , columnName , StringComparison . Ordinal ) )
135- ?? Properties . Find ( p => string . Equals ( p . Name , columnName , StringComparison . OrdinalIgnoreCase ) ) ;
136-
137- if ( property == null && MatchNamesWithUnderscores )
138- {
139- property = Properties . Find ( p => string . Equals ( p . Name , columnName . Replace ( "_" , "" ) , StringComparison . Ordinal ) )
140- ?? Properties . Find ( p => string . Equals ( p . Name , columnName . Replace ( "_" , "" ) , StringComparison . OrdinalIgnoreCase ) ) ;
141- }
141+ var property = MatchFirstOrDefault ( Properties , columnName , static p => p . Name ) ;
142142
143143 if ( property != null )
144144 return new SimpleMemberMap ( columnName , property ) ;
@@ -174,6 +174,54 @@ public SqlMapper.IMemberMap GetMember(string columnName)
174174 /// </summary>
175175 public static bool MatchNamesWithUnderscores { get ; set ; }
176176
177+ static T MatchFirstOrDefault < T > ( IList < T > members , string name , Func < T , string > selector ) where T : class
178+ {
179+ if ( members is { Count : > 0 } )
180+ {
181+ // try exact first
182+ foreach ( var member in members )
183+ {
184+ if ( string . Equals ( name , selector ( member ) , StringComparison . Ordinal ) )
185+ {
186+ return member ;
187+ }
188+ }
189+ // then exact ignoring case
190+ foreach ( var member in members )
191+ {
192+ if ( string . Equals ( name , selector ( member ) , StringComparison . OrdinalIgnoreCase ) )
193+ {
194+ return member ;
195+ }
196+ }
197+ if ( MatchNamesWithUnderscores )
198+ {
199+ // same again, minus underscore delta
200+ name = name ? . Replace ( "_" , "" ) ;
201+ foreach ( var member in members )
202+ {
203+ if ( string . Equals ( name , selector ( member ) ? . Replace ( "_" , "" ) , StringComparison . Ordinal ) )
204+ {
205+ return member ;
206+ }
207+ }
208+ foreach ( var member in members )
209+ {
210+ if ( string . Equals ( name , selector ( member ) ? . Replace ( "_" , "" ) , StringComparison . OrdinalIgnoreCase ) )
211+ {
212+ return member ;
213+ }
214+ }
215+ }
216+ }
217+ return null ;
218+ }
219+
220+ internal static bool EqualsCI ( string x , string y )
221+ => string . Equals ( x , y , StringComparison . OrdinalIgnoreCase ) ;
222+ internal static bool EqualsCIU ( string x , string y )
223+ => string . Equals ( x ? . Replace ( "_" , "" ) , y ? . Replace ( "_" , "" ) , StringComparison . OrdinalIgnoreCase ) ;
224+
177225 /// <summary>
178226 /// The settable properties for this typemap
179227 /// </summary>
0 commit comments