11using System ;
2+ using System . Collections . Generic ;
23using System . Diagnostics ;
4+ using System . Linq ;
5+ using System . Reflection ;
36using System . Runtime . InteropServices ;
47using System . Runtime . Serialization ;
58
@@ -79,49 +82,56 @@ public static NewReference tp_new(BorrowedReference tp, BorrowedReference args,
7982 BorrowedReference bases = Runtime . PyTuple_GetItem ( args , 1 ) ;
8083 BorrowedReference dict = Runtime . PyTuple_GetItem ( args , 2 ) ;
8184
82- // We do not support multiple inheritance, so the bases argument
83- // should be a 1-item tuple containing the type we are subtyping.
84- // That type must itself have a managed implementation. We check
85- // that by making sure its metatype is the CLR metatype.
85+ // Extract interface types and base class types.
86+ var interfaces = new List < Type > ( ) ;
87+ var baseType = new List < ClassBase > ( ) ;
8688
87- if ( Runtime . PyTuple_Size ( bases ) != 1 )
89+ var cnt = Runtime . PyTuple_GetSize ( bases ) ;
90+
91+ for ( uint i = 0 ; i < cnt ; i ++ )
8892 {
89- return Exceptions . RaiseTypeError ( "cannot use multiple inheritance with managed classes" ) ;
93+ var base_type2 = Runtime . PyTuple_GetItem ( bases , ( int ) i ) ;
94+ var cb2 = ( ClassBase ) GetManagedObject ( base_type2 ) ;
95+ if ( cb2 != null )
96+ {
97+ if ( cb2 . type . Valid && cb2 . type . Value . IsInterface )
98+ interfaces . Add ( cb2 . type . Value ) ;
99+ else baseType . Add ( cb2 ) ;
100+ }
90101 }
91-
92- BorrowedReference base_type = Runtime . PyTuple_GetItem ( bases , 0 ) ;
93- BorrowedReference mt = Runtime . PyObject_TYPE ( base_type ) ;
94-
95- if ( ! ( mt == PyCLRMetaType || mt == Runtime . PyTypeType ) )
102+ // if the base type count is 0, there might still be interfaces to implement.
103+ if ( baseType . Count == 0 )
96104 {
97- return Exceptions . RaiseTypeError ( "invalid metatype" ) ;
105+ baseType . Add ( new ClassBase ( typeof ( object ) ) ) ;
98106 }
99107
100- // Ensure that the reflected type is appropriate for subclassing,
101- // disallowing subclassing of delegates, enums and array types.
108+ // Multiple inheritance is not supported, unless the other types are interfaces
109+ if ( baseType . Count > 1 )
110+ {
111+ return Exceptions . RaiseTypeError ( "cannot use multiple inheritance with managed classes" ) ;
112+ }
102113
103- if ( GetManagedObject ( base_type ) is ClassBase cb )
114+ var cb = baseType [ 0 ] ;
115+ try
104116 {
105- try
106- {
107- if ( ! cb . CanSubclass ( ) )
108- {
109- return Exceptions . RaiseTypeError ( "delegates, enums and array types cannot be subclassed" ) ;
110- }
111- }
112- catch ( SerializationException )
117+ if ( ! cb . CanSubclass ( ) )
113118 {
114- return Exceptions . RaiseTypeError ( $ "Underlying C# Base class { cb . type } has been deleted ") ;
119+ return Exceptions . RaiseTypeError ( "delegates, enums and array types cannot be subclassed ") ;
115120 }
116121 }
122+ catch ( SerializationException )
123+ {
124+ return Exceptions . RaiseTypeError ( $ "Underlying C# Base class { cb . type } has been deleted") ;
125+ }
117126
118127 BorrowedReference slots = Runtime . PyDict_GetItem ( dict , PyIdentifier . __slots__ ) ;
119128 if ( slots != null )
120129 {
121130 return Exceptions . RaiseTypeError ( "subclasses of managed classes do not support __slots__" ) ;
122131 }
123132
124- // If __assembly__ or __namespace__ are in the class dictionary then create
133+ // If the base class has a parameterless constructor, or
134+ // if __assembly__ or __namespace__ are in the class dictionary then create
125135 // a managed sub type.
126136 // This creates a new managed type that can be used from .net to call back
127137 // into python.
@@ -130,10 +140,12 @@ public static NewReference tp_new(BorrowedReference tp, BorrowedReference args,
130140 using var clsDict = new PyDict ( dict ) ;
131141 if ( clsDict . HasKey ( "__assembly__" ) || clsDict . HasKey ( "__namespace__" ) )
132142 {
133- return TypeManager . CreateSubType ( name , base_type , clsDict ) ;
143+ return TypeManager . CreateSubType ( name , baseType , interfaces , clsDict ) ;
134144 }
135145 }
136146
147+ var base_type = Runtime . PyTuple_GetItem ( bases , 0 ) ;
148+
137149 // otherwise just create a basic type without reflecting back into the managed side.
138150 IntPtr func = Util . ReadIntPtr ( Runtime . PyTypeType , TypeOffset . tp_new ) ;
139151 NewReference type = NativeCall . Call_3 ( func , tp , args , kw ) ;
0 commit comments