Skip to content

[TrimmableTypeMap] Handle generic invoker type resolution at runtime #11046

@simonrozsival

Description

@simonrozsival

Updated Analysis: Generic Invoker Types Are Not a Real Problem

Original Concern

The legacy GetInvokerType has a MakeGenericType path for generic C# types. The concern was that the trimmable type map would not handle this.

Investigation Result: All Android invokers are non-generic C# types

Java uses type erasure for generics. The Mono.Android binding generator reflects this — all generated interfaces and their invokers are non-generic C# types, even when the Java type has generic parameters:

// java.util.Iterator<E> → non-generic C# interface + non-generic invoker
[Register("java/util/Iterator", "", "Java.Util.IIteratorInvoker")]
[JavaTypeParameters(new string[] {"E"})]  // metadata only, not a C# generic param
public partial interface IIterator : IJavaObject, IJavaPeerable { ... }

[Register("java/util/Iterator", DoNotGenerateAcw=true)]
internal partial class IIteratorInvoker : Java.Lang.Object, IIterator { ... }

The same pattern applies to all 90+ generic Java interfaces:

  • java/util/ListIList + IListInvoker (non-generic)
  • java/util/MapIMap + IMapInvoker (non-generic)
  • android/os/Parcelable$CreatorIParcelableCreator + IParcelableCreatorInvoker (non-generic)
  • etc.

Runtime Flow (Legacy)

  1. Java returns an object implementing java.util.Iterator
  2. GetJavaToManagedType("java/util/Iterator")Java.Util.IIterator (non-generic)
  3. Since IIterator is an interface, GetInvokerType(typeof(IIterator)) is called
  4. IIterator has zero generic arguments → takes the simple path: Assembly.GetType("Java.Util.IIteratorInvoker")
  5. IIteratorInvoker is instantiated — no MakeGenericType involved

The MakeGenericType Path Is Dead Code (for Android)

The generic invoker resolution in JavaObjectExtensions.GetInvokerType (lines 137-146) and ManagedTypeManager.GetInvokerTypeCore (lines 48-59) handles C# generics like IFoo<T>IFooInvoker<T>. But:

  • No generated Mono.Android binding produces generic C# invoker types
  • No Java.Interop or Java.Base types produce generic C# invoker types
  • The code appears to be defensive/future-proofing for a pattern not currently used

Impact on Trimmable Type Map

Low to none. The trimmable path stores InvokerType as a pre-resolved non-generic type reference in the proxy attribute. Since all invokers in Mono.Android are non-generic, this works correctly:

TypeMap entry: "java/util/Iterator" → IIterator_Proxy
IIterator_Proxy.InvokerType → typeof(IIteratorInvoker)  // non-generic, resolves fine

Recommendation

This issue can be deprioritized or closed. The generic invoker scenario is theoretical — it would only matter if:

  1. A third-party binding library creates actual C# generic interfaces (not just [JavaTypeParameters])
  2. Someone uses the Java.Interop [JniTypeSignature] pattern with generic C# types

Neither scenario is common or blocking for .NET 11.

Metadata

Metadata

Assignees

No one assigned

    Labels

    copilot`copilot-cli` or other AIs were used to author thisneeds-triageIssues that need to be assigned.trimmable-type-map

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions