C# 9.0 – Specification – Covariant Return Types
Índice general – C# 9.0 – Specification
AVISO (02/10/2020): Después de publicar esta entrada y probarla con la RC1 de Visual Studio 16.8.0 publicada recientemente, parece que no funciona como se espera. Puedes ver más información sobre esto en https://github.com/dotnet/csharplang/issues/49 y https://github.com/dotnet/roslyn/issues/43188 y https://github.com/dotnet/csharplang/issues/3562.
Actualización: Hay un bug en RC1 que causa una excepción de tipo TypeLoadException, y que quedará resuelto en RC2.El 13 de Octubre de 2020, aparece la RC2 de .NET 5, y efectivamente, el bug ha quedado resuelto.
Introducción
Covariant return, o return type covariant, es una característica del lenguaje por la cuál, podemos sobreescribir un método de una clase base que tiene un tipo no especificado, por un método cuyo tipo sí es más específico.
Como siempre, la mejor forma de entender bien esto, es verlo con ejemplos, así que vamos a ello.
Antes de C# 9
La primera acción es ponernos en contexto o situación, por lo que vamos a escribir un código que sea el que estábamos acostumbrados a utilizar.
using System; var p = new Person("Mary", 39).Get(); Console.WriteLine($"{p.Name} is {p.Age} years old!"); var s = new Student("Jorge", 18, "Group A"); Console.WriteLine($"{s.Name} is {s.Age} years old and has the group {s.Group}!"); public class Person { public string Name { get; } public int Age { get; } public Person(string name, int age) { Name = name; Age = age; } public virtual Person Get() => new(Name, Age); } public class Student : Person { public string Group { get; } public Student(string name, int age, string group) : base(name, age) { Group = group; } public override Person Get() => new(Name, Age); }
Como podemos ver, el método Get en Student, devuelve un objeto de tipo Person.
Ahora bien, en nuestro caso nos gustaría devolver un objeto más concreto, un objeto de tipo Student.
Y es precisamente aquí donde entra en juego la nueva característica del lenguaje.
Covarianza en la devolución de objetos en C# 9
El ejemplo anterior quedaría en nuestro caso de la siguiente forma:
using System; var p = new Person("Mary", 39).Get(); Console.WriteLine($"{p.Name} is {p.Age} years old!"); var s = new Student("Jorge", 18, "Group A"); Console.WriteLine($"{s.Name} is {s.Age} years old and has the group {s.Group}!"); public class Person { public string Name { get; } public int Age { get; } public Person(string name, int age) { Name = name; Age = age; } public virtual Person Get() => new(Name, Age); } public class Student : Person { public string Group { get; } public Student(string name, int age, string group) : base(name, age) { Group = group; } public override Student Get() => new(Name, Age, Group); }
Aquí devolvemos un objeto de tipo Student en lugar de Person.
Conclusiones
De esta forma, podemos «jugar» con los objetos que queremos devolver para devolver uno más concreto en lugar del genérico.
Antes, teníamos que hacer workarounds para intentar solventar el problema, pero ahora y con esta característica, tenemos todo más cohexionado.
Happy Coding!