-
Notifications
You must be signed in to change notification settings - Fork 748
.NET objects returned as interface 'lose' their most-derived type identity #2213
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Maybe we should fix the def is_clr_instance(obj, T):
if hasattr(obj, '__implementation__'):
return isinstance(obj.__implementation__, T)
else:
return isinstance(obj, T) and a similar one for |
We can't adjust |
@filmor won't fix then? The simple method above is a descent workaround. |
I'll take any mechanism which just tells me if an particular interface is implemented dynamically so we can upcast to get to the subclass fields/props/methods 'statically'' without having to check |
It's quite un-OOP to just assume that a particular interface might be implemented. If you want to use a property, make sure that the returned interface has that property. You'd have to do that in C# as well. The main issue here is that |
This isn't always going to be possible though - hierarchies of interfaces do exist (like the one I've "inherited", ho ho ho). I absolutely agree in the real world this problem is the result of a terrible design but it isn't going to be practical or possible to flatten them all out and add N hundred methods returning N hundred possible interfaces/having N homogenous Collections when they all share a common interface ancestor (or crunching Z hundred members down into one mega-interface). In C# at least you can test the returned interface to see if it's actually a subinterface and then cast it before trying access the property (or do it in one go with I don't think it's unreasable to ask a object of I totally agree that modifying def try_cast(T, obj):
return T(obj) if clr.GetClrType(T).IsInstanceOfType(obj) else None
f = Factory()
obj = f.PolymorphicObject # Defined as returns IBaseInterface
subinterfaceIX = clr.GetClrType(IDerivedInterfaceX).IsInstanceOfType(obj) # <IDerivedInterfaceX>, same a C# code
obj = IDerivedInterfaceX(obj) # Happy Days
#obj = IDerivedInterfaceY(obj) # Crashy Days
for obj2 in f.HeterogenousPolymophicCollection: # Defined as IEnumerable<IBaseInterface>
derivedIX = try_cast(IDerivedInterfaceX, obj2) # None then <IDerivedInterfaceX>, same as C# code
derivedIY = try_cast(IDerivedInterfaceY, obj2) # <IDerivedInterfaceY>then None, same as C# code I don't doubt there's a neater way to do this and/or a having a package-provided helper function but for now we're sorted - thanks. |
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. |
@filmor basically, .NET's |
@filmor is it planned to add this? Otherwise am I allowed to contribute this? |
PRs are always welcome! Maybe line out here on in a separate issue what you would like to add s.t. we can discuss it up-front (we can also discuss directly over code, though) :) |
Annoyingly, you cannot override protected methods in Python.NET. And this is a big problem for AbstractPdfDocumentEventHandler, as you need to override an `abstract protected` method. Relevant issues: - pythonnet/pythonnet#2213 - pythonnet/pythonnet#2571 I've tried making a Python.NET fork, which allows you to override: - https://github.com/Eswcvlad/pythonnet/tree/protected-override But since the issue has been hanging for a while, I doubt it will be fixed soon. And making a dependency on a fork is not great... Changing this on iText side is not good as well, as it makes the C# API worse... For now, I've patched all AbstractPdfDocumentEventHandler OnAcceptedEvent methods in iText to be public, but this is a very bad solution, as: - You would need to track any new subclasses on updates and patch them as well. - You would need to update these patches for every release. - This only handles one method, while this is a global problem. - If you add another library, which also derives from AbstractPdfDocumentEventHandler, then it will not work, if OnAcceptedEvent remained "protected" there. But it is better than nothing...
Environment
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:
Python client code behaves differently than C# client code:
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?
The text was updated successfully, but these errors were encountered: