Skip to content
This repository was archived by the owner on Aug 27, 2026. It is now read-only.
This repository was archived by the owner on Aug 27, 2026. It is now read-only.

C# 8 Language Features for API-30 Bindings #509

Closed

Description

@jonpryor

Whenever API-30 comes out, we would like to adopt C#8 features as part of the new binding in the following ways:

  1. Default interface members for added interface & abstract methods
  2. New Java interfaces containing nested types will "remain" nested in the C# binding. Existing nested types will be "unchanged", structurally speaking.

TODO:

Determining newly added members

Within a xamarin-android/src/Mono.Android build, api-merge.exe is used to "merge" the various API XML files together so that we know in which API level a member was added. This information is in the //@merge.SourceFile attribute, e.g.

<field
    name="ACTIVITY_RECOGNITION" …
    merge.SourceFile="..\..\bin\BuildDebug\api\api-29.xml.in"
/>

Structure of existing types is not changed

Consider the android.view.MenuItem and android.view.MenuItem.OnActionExpandListener interfaces: MenuItem.OnActionExpandListener is nested within the MenuItem interface.

Versions of C# prior to C#8 didn't support nesting types within interfaces, so the C#7 binding of these types is:

partial interface IMenuItem {
}
partial interface IMenuItemOnActionExpandListener {
}

This structure will not change for existing types.

Structure of new types will require C#8 features

For types added in API-30, the types will be nested. If the Java declaration is:

package android.example;

public interface Outer {
    public static final int O = 1;
    public interface Nested {
        public static final int N = 2;
    }
}

Then the C# declaration will mirror the Java structure:

namespace Android.Example {
    public partial interface IOuter {
        public const int O = 1;
        public partial interface INested {
            public const int N = 2;
        }
    }
}

Default Interface Members to maintain compatibility

When a new abstract method is added to an abstract class, or a new required (non-default) method is added to a Java interface -- as was done with android.database.Cursor in API-11, API-19, API-23, and API-29 -- then a new default interface method should be emitted which does a throw new AbstractMethodError().

For example, consider ICursor for API-10:

partial interface ICursor {
    // ...
}

API-11 added a new Cursor.getType(int) method. If we had C#8 during API-11, we could have done:

// for API-11
partial interface ICursor {
    // … same as API-10

    // Added in API-11
    int GetType (int columnIndex)
    {
        throw new AbstractMethodError ();
    }
}

All interfaces updated to contain static members

As C#7 didn't support static members, if an interface had any static members, e.g. public static final int fields, then those fields were emitted into a class:

namespace Android.OS {
    public partial interface IParcelable : IJavaObject, IJavaPeerable {
        // …
    }
    public partial class Parcelable {
        [Register ("CONTENTS_FILE_DESCRIPTOR")]
        public const int ContentsFileDescriptor = (int) 1;

        [Register ("PARCELABLE_WRITE_RETURN_VALUE")]
        [Obsolete ("This constant will be removed in the future version. Use Android.OS.ParcelableWriteFlags enum directly instead of this field.")]
        public const Android.OS.ParcelableWriteFlags ParcelableWriteReturnValue = (Android.OS.ParcelableWriteFlags) 1;
    }
}

For compatibility, we cannot remove the Parcelable type. What we can and should do, is add all of those members to the interface as well, and make the Parcelable type [Obsolete(error:true)]

namespace Android.OS {
    public partial interface IParcelable : IJavaObject, IJavaPeerable {
        // …

        [Register ("CONTENTS_FILE_DESCRIPTOR")]
        public const int ContentsFileDescriptor = (int) 1;

        [Register ("PARCELABLE_WRITE_RETURN_VALUE")]
        public const Android.OS.ParcelableWriteFlags ParcelableWriteReturnValue = (Android.OS.ParcelableWriteFlags) 1;
    }
    [Obsolete("Use the IParcelable type", error:true)]
    public partial class Parcelable {
        [Register ("CONTENTS_FILE_DESCRIPTOR")]
        [Obsolete("Use IParcelable.ContentsFileDescriptor", error:true)]
        public const int ContentsFileDescriptor = (int) 1;

        [Register ("PARCELABLE_WRITE_RETURN_VALUE")]
        [Obsolete ("This constant will be removed in the future version. Use Android.OS.ParcelableWriteFlags.ReturnValue instead of this field.")]
        public const Android.OS.ParcelableWriteFlags ParcelableWriteReturnValue = (Android.OS.ParcelableWriteFlags) 1;
    }
}

This will "duplicate" members. We should [Obsolete] the Parcelable (and similar) types in API-30.

New members should only be added to the interface, not the "constants class". The actual constants class, ParcelableConsts, should be removed from the binding for API-30, as it will be Obsolete with error:true for over a year by the time this is expected to happen.

Activity

  1. added this to the milestone on Oct 31, 2019
  2. jonpryor commented on Feb 6, 2020

    @jonpryor
    ContributorAuthor

    Additional/related changes:

    For API-30, we should [Obsolete(error:true)] "interface proxy" types such as Android.Content.ComponentCallbacks2, which contains fields for the android.content.ComponentCallbacks2 interface and lives "alongside" the Android.Content.IComponentCallbacks2 interface. Additionally, all of these fields should be moved into the appropriate C# interface, e.g. every field within Android.Content.ComponentCallbacks2 should reside in the Android.Content.IComponentCallbacks2 type, using C#8 default interface members.

    We should also [Obsolete(error:true)] all of the nested InterfaceConsts types, such as Android.OS.Binder.InterfaceConsts.

    We should also [Obsolete(error:true)] all members which are already [Obsolete].

  3. JonDouglas commented on Feb 19, 2020

    @JonDouglas

    FWIW: API 30 dropped today. Here is the initial diff:

    https://developer.android.com/sdk/api_diff/r-dp1/changes

    Final APIs should be released in June sometime.

  4. changed the title [-]Binding API-30[/-] [+]C# 8 Language Features for API-30 Bindings[/+] on Feb 21, 2020
  5. 4 remaining items

  6. jpobst commented on Mar 16, 2020

    @jpobst
    Contributor

    Completed for 16.6! 🎉

  7. jpobst commented on Mar 16, 2020

    @jpobst
    Contributor

    I just noticed @jonpryor's additional comment of things to deprecate. These did not make it for 16.6, I moved them to a new ticket to track for future API-30 previews.

    #602

  8. modified the milestones: , Published: 10.3 (d16-6) on Mar 1, 2021
  9. locked and limited conversation to collaborators on Apr 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions