.NET objects returned as interface 'lose' their most-derived type identity
See original GitHub issueEnvironment
- 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?
Issue Analytics
- State:
- Created a month ago
- Comments:8 (6 by maintainers)
Top GitHub Comments
Yeah, I think I’ll prepare a PR for adding functions for this. We should have probably added these right when the change in behaviour happened.
We can’t adjust
isinstance
andissubclass
(which is correct anyhow, one would need to adjusttype(obj)
) without also going back to the “old” behaviour of trying to resolve all fields, properties and methods dynamically. Otherwise,if isinstance(obj, SomeClass): obj.PropertyDefinedInSomeClass
would fail.