dotnet / android

.NET for Android provides open-source bindings of the Android SDK for use with .NET managed languages such as C#
MIT License
1.89k stars 523 forks source link

Missing exception-free JavaCast overload #9038

Open mattleibow opened 1 week ago

mattleibow commented 1 week ago

Android framework version

net8.0-android

Affected platform version

.NET 8

Description

When writing some code that does not have a specific .NET type, or if the linker removes the .NET type because it is not used, there is no way to check to see if the type is implementing an interface or has a specific base type.

For example, I am using Glide to load a Drawable and then I want to see if it implements the IAnimatable interface. In debug builds this works because the AnimationDrawable type happens to be in the .NET type system. When the linker runs through the code, that type is never referenced so it is removed. This causes the runtime behavior to be wrong for an if block like this:

if (myDrawableFromJava is IAnimatable)

Similarly, if I have a slim binding (or chose not to bind everything) then the .NET type will never exist at all.

The app still runs because it uses the DrawableInvoker type to do things. This invoker does not have the interface to the .NET type check fails.

To get around this issue, I want to use the JavaCast<T>() extension method, but that now throws an exception if the type is not what I am casting.

Is there an overload or alternative that will allow be to check the types on the Java side to see if an interface or base type is valid and then return the instance that is of that type?

Steps to Reproduce

This is the core issue: https://github.com/dotnet/maui/pull/22874

Did you find any workaround?

public static TResult? TryJavaCast<[DynamicallyAccessedMembers (Constructors)] TResult>(this IJavaObject? instance)
    where TResult : class, IJavaObject
{
    try
    {
        return instance.JavaCast<TResult>();
    }
    catch
    {
        return null;
    }
}

Relevant log output

No response