3

I am trying to generate Xamarin bindings for a proprietary Android library (in other words, unfortunately I cannot share this library here). However I run into a problem with polymorphism. Here is the situation.

The library exposes 3 interfaces Location, MobilityProfile and Trip all extend the interface Reading.

The library also has an interface Measurement which contains Reading getReading(); method which should always return one of the 3 mentioned interfaces (Location, MobilityProfile or Trip).

I generated the bindings and compiled the binding project which works well. The next step would be to use the Xamarin.Android binding in my Xamarin project like this:

public void ProcessReading(IReading reading)
{
    if (reading == null)
        return null;

    switch (reading)
    {
        case ILocation location:
            // Process location
            break;
        case IMobilityProfile mobilityProfile:
            // Process mobility profile
            break;
        case ITrip trip:
            // Process trip
            break;
        default:
            throw new NotSupportedException($"Processing the type '{reading.GetType().FullName}' is not supported.");
    }
}

Now here I end up in the default condition because the reading parameter is of type IReadingInvoker. Can anybody advise how I can solve this issue?

Maurits van Beusekom
  • 5,579
  • 3
  • 21
  • 35

2 Answers2

5

Xamarin.Android binding library couldn't map the Java instance to its C# interface when your library returns it that way, so casting never works.

Plz use Android.Runtime.Extensions.JavaCast<ILocation>(readingInstace) and so on for other types.

Probaly try-catch is required.

Cheers.

Tuyến Vũ
  • 131
  • 4
  • Thanks @tuyến-vũ this was exactly the information I was looking for. Just in case others are wondering, more information can be found here: https://developer.xamarin.com/api/member/Android.Runtime.Extensions.JavaCast%7BTResult%7D/p/Android.Runtime.IJavaObject/ – Maurits van Beusekom Apr 23 '18 at 08:44
1

Because you are receiving the base interface object the switch statement won't be able to identify it as one of the other child interfaces. At least not in the way that you are expecting it to.

Based off of your comment and some additional checking, try the below, and breakpoint in the catch brackets of each one, just to confirm that it's possible to explicitly cast to one of your derived interfaces.

public void ProcessReading(IReading reading)
{
    if (reading == null)
        return null;

    try
    {
        var castReading = (ILocation) reading; 
        // Process location
    }
    catch
    {
        //exception hit
    }

    try
    {
        var castReading = (IMobilityProfile ) reading; 
        // Process mobility profile
    }
    catch
    {
        //exception hit
    }

    try
    {
        var castReading = (ITrip ) reading; 
        // Process trip
    }
    catch
    {
        //exception hit
    }
}

definitely not the neatest way. But it's a bit of a faff to use a switch statement to determine type because of the reasons highlighted in this stack overflow question: Here.

Edit: in review looks like you would need an explicit cast, which means you can't reliably use conditional operators as an explicit cast will throw an exception if it's not able to cast the object. Source.

JoeTomks
  • 3,243
  • 1
  • 18
  • 42
  • I have tried as you suggested but unfortunately I get the same result. The code ends-up in the `else` block and throws the exception: "Processing the type 'IReadingInvoker' is not supported." – Maurits van Beusekom Apr 20 '18 at 14:14
  • @MauritsvanBeusekom made a quick edit so that you can just test an explicit cast. – JoeTomks Apr 20 '18 at 14:24
  • As I expected, that results in the same problem. I mean under the hood the `as` keyword also performs the explicit cast. I feel it is related to the fact that Xamarin.Android needs an object that implements the `IJavaObject` type and therefore generates a `I...Resolver` class that implements the `Java.Lang.Object` class. However I am a bit lost in the how and why and how to handle this correctly in a way I can solve my issue: https://learn.microsoft.com/en-us/xamarin/android/platform/java-integration/working-with-jni#binding-interfaces – Maurits van Beusekom Apr 20 '18 at 14:36