Skip to content

Incorrect override or virtual Method Modifiers

Jonathan Pobst edited this page Jul 12, 2022 · 4 revisions

When you need to override a method in Java you add the @Override annotation:

public class MyBaseClass
{
    void doSomething () { ... }
}

public class MyClass : MyBaseClass
{
   @Override
   void doSomething () { ... }
}

However, this information is used by the Java compiler and then discarded. This means it is not available in the compiled .jar for the bindings process to copy to C#. The bindings process has a complex algorithm where it attempts to determine if a method should be virtual or override, but sometimes it makes mistakes.

This can lead to instances like trying to override an interface method instead of declaring it as virtual:

public interface ICloneable
{
    Java.Lang.Object Clone ();
}

public class MyClass : Java.Lang.Object, ICloneable
{
    public override void Java.Lang.Object Clone () { ... }
}

This results in compilation errors like:

Error CS0115: 'MyClass.Clone()': no suitable method found to override

Beginning in Visual Studio 16.9 (VSMac 8.9), the metadata attribute managedOverride has been added, allowing one to explicitly tell the bindings process if a method needs to be virtual or override.

<attr path="/api/package[@name='com.example']/class[@name='MyClass']/method[@name='clone']" name="managedOverride">virtual</attr>

Now the bindings process knows the method should be virtual, which fixes the compilation error:

public interface ICloneable
{
    Java.Lang.Object Clone ();
}

public class MyClass : Java.Lang.Object, ICloneable
{
    public virtual void Java.Lang.Object Clone () { ... }
}

Note: Sometimes you need the opposite: the method is generated as virtual when it should be override. Using the value of override will fix this case:

<attr path="/api/package[@name='com.example']/class[@name='MyClass']/method[@name='clone']" name="managedOverride">override</attr>

Additionally, sometimes the correct code is to omit both virtual and override. For example, when the method is in a sealed type.

In this case, the value none can be provided:

<attr path="/api/package[@name='com.example']/class[@name='MyClass']/method[@name='clone']" name="managedOverride">none</attr>

The value none value was added in .NET 7 / Xamarin.Android 13.1 (Visual Studio 2022 17.4).