-
Notifications
You must be signed in to change notification settings - Fork 758
Description
Environment
- Pythonnet version: 3.0.1
- Python version: 3.10.11
- Operating System: Windows 11
- .NET Runtime: .NET Framework 4.8.9167.0
Details
-
Describe what you were trying to get done.
Return an interface derived from the one declared as a method or property's return type and be able to do RTTI to detect the type of derived interface returned. Do the same with a heterogeneous collection where the collection's type is declared as a collection of BaseInterface but the members are implementations of DerivedInterfaces. -
What commands did you run to trigger this issue?
Given some C# library code:
public interface IBaseInterface { }
public interface IDerivedInterfaceX : IBaseInterface { }
public interface IDerivedInterfaceY : IBaseInterface { }
public class ConcreteX : IDerivedInterfaceX { }
public class ConcreteY : IDerivedInterfaceY { }
public class Factory
{
public IBaseInterface PolymorphicObject => new ConcreteX();
public IEnumerable<IBaseInterface> HeterogenousPolymorphicCollection=> new IBaseInterface[] { new ConcreteY(), new ConcreteX() };
}
Python client code behaves differently than C# client code:
static void Main(string[] args)
{
Factory f = new();
IBaseInterface obj = f.PolymorphicObject;
bool isDerived = obj is IDerivedInterfaceX; // true
foreach (IBaseInterface obj2 in f.HeterogenousPolymorphicCollection)
{
bool isDerivedX = obj2 is IDerivedInterfaceX; // false then true
bool isDerivedY = obj2 is IDerivedInterfaceY; // true then false
}
}
f = Factory()
obj = f.PolymorphicObject # Type is IBaseInterface FOREVER
isDerived = isinstance(obj, IDerivedInterfaceX) # Always False
isSubclass = issubclass(type(obj), IDerivedInterfaceX) # Always False
for obj2 in f.HeterogenousPolymorphicCollection: # Type is IBaseInterface FOREVER
isDerivedX = isinstance(obj2, IDerivedInterfaceX) # ALWAYS FALSE
isDerivedY = isinstance(obj2, IDerivedInterfaceY) # ALWAYS FALSE
We know it's possible to "cheat" by testing obj.__implementation__
's type but we'd rather keep everything as interfacey as possible :)
We know the official solution is to attempt to upcast the returned objects but of course this will throw an exception if it's not possible -- we'd like to examine the type returned to ensure no exception before we upcast.
Is there a nice, pretty solution?