@@ -343,11 +343,14 @@ private static ClassInfo GetClassInfo(Type type, ClassBase impl)
343343 Type tp ;
344344 int i , n ;
345345
346- MemberInfo [ ] info = type . GetMembers ( BindingFlags ) ;
346+ MemberInfo [ ] info = type . GetMembers ( BindingFlags | BindingFlags . FlattenHierarchy ) ;
347347 var local = new HashSet < string > ( ) ;
348348 var items = new List < MemberInfo > ( ) ;
349349 MemberInfo m ;
350350
351+ var snakeCasedAttributes = new HashSet < string > ( ) ;
352+ var originalMemberNames = info . Select ( mi => mi . Name ) . ToHashSet ( ) ;
353+
351354 // Loop through once to find out which names are declared
352355 for ( i = 0 ; i < info . Length ; i ++ )
353356 {
@@ -430,6 +433,28 @@ private static ClassInfo GetClassInfo(Type type, ClassBase impl)
430433 }
431434 }
432435
436+ void CheckForSnakeCasedAttribute ( string name )
437+ {
438+ if ( snakeCasedAttributes . Remove ( name ) )
439+ {
440+ // If the snake cased attribute is a method, we remove it from the list of methods so that it is not added to the class
441+ methods . Remove ( name ) ;
442+ }
443+ }
444+
445+ void AddMember ( string name , string snakeCasedName , PyObject obj )
446+ {
447+ CheckForSnakeCasedAttribute ( name ) ;
448+
449+ ci . members [ name ] = obj ;
450+
451+ if ( ! originalMemberNames . Contains ( snakeCasedName ) )
452+ {
453+ ci . members [ snakeCasedName ] = obj ;
454+ snakeCasedAttributes . Add ( snakeCasedName ) ;
455+ }
456+ }
457+
433458 for ( i = 0 ; i < items . Count ; i ++ )
434459 {
435460 var mi = ( MemberInfo ) items [ i ] ;
@@ -448,6 +473,7 @@ private static ClassInfo GetClassInfo(Type type, ClassBase impl)
448473 if ( name == "__init__" && ! impl . HasCustomNew ( ) )
449474 continue ;
450475
476+ CheckForSnakeCasedAttribute ( name ) ;
451477 if ( ! methods . TryGetValue ( name , out var methodList ) )
452478 {
453479 methodList = methods [ name ] = new MethodOverloads ( true ) ;
@@ -456,14 +482,15 @@ private static ClassInfo GetClassInfo(Type type, ClassBase impl)
456482
457483 if ( ! OperatorMethod . IsOperatorMethod ( meth ) )
458484 {
459- var snakeCasedName = name . ToSnakeCase ( ) ;
460- if ( snakeCasedName != name )
485+ var snakeCasedMethodName = name . ToSnakeCase ( ) ;
486+ if ( snakeCasedMethodName != name && ! originalMemberNames . Contains ( snakeCasedMethodName ) )
461487 {
462- if ( ! methods . TryGetValue ( snakeCasedName , out methodList ) )
488+ if ( ! methods . TryGetValue ( snakeCasedMethodName , out methodList ) )
463489 {
464- methodList = methods [ snakeCasedName ] = new MethodOverloads ( false ) ;
490+ methodList = methods [ snakeCasedMethodName ] = new MethodOverloads ( false ) ;
465491 }
466492 methodList . Add ( meth ) ;
493+ snakeCasedAttributes . Add ( snakeCasedMethodName ) ;
467494 }
468495 }
469496 continue ;
@@ -506,9 +533,7 @@ private static ClassInfo GetClassInfo(Type type, ClassBase impl)
506533 }
507534
508535 ob = new PropertyObject ( pi ) ;
509- var allocatedOb = ob . AllocObject ( ) ;
510- ci . members [ pi . Name ] = ob . AllocObject ( ) ;
511- ci . members [ pi . Name . ToSnakeCase ( ) ] = allocatedOb ;
536+ AddMember ( pi . Name , pi . Name . ToSnakeCase ( ) , ob . AllocObject ( ) ) ;
512537 continue ;
513538
514539 case MemberTypes . Field :
@@ -518,15 +543,14 @@ private static ClassInfo GetClassInfo(Type type, ClassBase impl)
518543 continue ;
519544 }
520545 ob = new FieldObject ( fi ) ;
521- allocatedOb = ob . AllocObject ( ) ;
522- ci . members [ mi . Name ] = allocatedOb ;
523546
524547 var pepName = fi . Name . ToSnakeCase ( ) ;
525548 if ( fi . IsLiteral )
526549 {
527550 pepName = pepName . ToUpper ( ) ;
528551 }
529- ci . members [ pepName ] = allocatedOb ;
552+
553+ AddMember ( fi . Name , pepName , ob . AllocObject ( ) ) ;
530554 continue ;
531555
532556 case MemberTypes . Event :
@@ -538,9 +562,7 @@ private static ClassInfo GetClassInfo(Type type, ClassBase impl)
538562 ob = ei . AddMethod . IsStatic
539563 ? new EventBinding ( ei )
540564 : new EventObject ( ei ) ;
541- allocatedOb = ob . AllocObject ( ) ;
542- ci . members [ ei . Name ] = allocatedOb ;
543- ci . members [ ei . Name . ToSnakeCase ( ) ] = allocatedOb ;
565+ AddMember ( ei . Name , ei . Name . ToSnakeCase ( ) , ob . AllocObject ( ) ) ;
544566 continue ;
545567
546568 case MemberTypes . NestedType :
@@ -552,6 +574,7 @@ private static ClassInfo GetClassInfo(Type type, ClassBase impl)
552574 }
553575 // Note the given instance might be uninitialized
554576 var pyType = GetClass ( tp ) ;
577+ CheckForSnakeCasedAttribute ( mi . Name ) ;
555578 // make a copy, that could be disposed later
556579 ci . members [ mi . Name ] = new ReflectedClrType ( pyType ) ;
557580 continue ;
0 commit comments