-
Notifications
You must be signed in to change notification settings - Fork 50
Covariant Return Types (Class)
Imagine the following Java code:
public abstract class Animal
{
abstract Animal get ();
}
public class Dog : Animal
{
@Override
public Dog get ()
{
return new Dog ();
}
}
The Dog.get ()
method implements the abstract Animal.get ()
as required by the abstract
Animal
class, however it changes the return type from Animal
to Dog
. Changing the return type to a more specific type (Dog
inherits Animal
) is called a covariant return type. This is allowed in Java, however it is historically not allowed in C#. (Xamarin in .NET6 will support C# 9, which supports many -but not all- cases of covariant return types.)
This scenario is overriding an abstract
class method. A similar scenario is implementing an interface: Covariant Return Types (Interface).
The above example generates the following C# code:
// Metadata.xml XPath class reference: path="/api/package[@name='my.package']/class[@name='Animal']"
[global::Android.Runtime.Register ("my/package/Dog", DoNotGenerateAcw=true)]
public abstract partial class Animal : Java.Lang.Object
{
// Metadata.xml XPath method reference: path="/api/package[@name='my.package']/class[@name='Animal']/method[@name='get']"
[Register ("get", "()Lmy/package/Animal;", "GetGetHandler")]
public abstract unsafe global::My.Package.Animal Get ();
}
// Metadata.xml XPath class reference: path="/api/package[@name='my.package']/class[@name='Dog']"
[global::Android.Runtime.Register ("my/package/Dog", DoNotGenerateAcw=true)]
public partial class Dog : global::My.Package.Dog
{
// Metadata.xml XPath method reference: path="/api/package[@name='my.package']/class[@name='Dog']/method[@name='get']"
[Register ("get", "()Lmy/package/Dog;", "GetGetHandler")]
public virtual unsafe global::My.Package.Dog Get ()
{
...
}
}
That is, looking at the generated code, you can see that the Get
method was generated, however it does not have the same return type as the abstract
Animal.Get ()
method, and thus:
- The Java-to-C# code generator did not mark
Dog.Get ()
as anoverride
ofAnimal.Get ()
- The C# compiler does not think the
Dog
class implements theabstract
methodAnimal.Get ()
Compiling this code causes a C# error:
Error CS0534 'My.Package.Dog' does not implement inherited abstract member 'My.Package.Animal.Get()'
In order to fix this, we need to instruct the Java-to-C# code generator to use My.Package.Animal
as a return type instead of My.Package.Dog
. This can be done with the managedReturn
type of metadata
, which changes the "managed" (C#) method "return" type. Using the XPath specified in the generated method above, the metadata
would look like this:
<attr path="/api/package[@name='my.package']/class[@name='Dog']/method[@name='get']" name="managedReturn">My.Package.Animal</attr>
With this metadata
in place, the following C# method is generated, which satisfies the Animal
abstract
contract:
// Metadata.xml XPath method reference: path="/api/package[@name='my.package']/class[@name='Dog']/method[@name='get']"
[Register ("clone", "()Lmy/package/Animal;", "GetCloneHandler")]
public virtual unsafe global::My.Package.Animal Get ()
{
...
}