In this article, it is written that in C# 8.0 new feature of convariant return type will be included as the community asking for this feature for quite a long time.
Can anybody explain why and when this feature is required with practical example ?
Software Engineering Stack Exchange is a question and answer site for professionals, academics, and students working within the systems development life cycle. It only takes a minute to sign up.
Sign up to join this communityIn this article, it is written that in C# 8.0 new feature of convariant return type will be included as the community asking for this feature for quite a long time.
Can anybody explain why and when this feature is required with practical example ?
Firstly, it is worth noting that the article is very likely wrong. There is currently a long list of features officially earmarked for C# 8.0, but covariant return types is not one of them. That feature is scheduled for X.0, ie it needs to appear in a major release, so might appear for 8.0 (but that's incredibly unlikely), more likely will be in 9.0 or 10.0 etc.
As for what use is the feature, have a read of the original Roslyn issue from three years ago. It has numerous uses around being able to narrow the return type within methods in derived types, eg an implementation of a factory interface could specify that it returns a concrete type, rather than an interface.
For example, using generics, we can do something like:
public interface IFactory<T>
{
T Create();
}
public class Foo{}
public class FooFactory : IFactory<Foo>
{
public Foo Create() => null;
}
But if IFactory
instead uses further interfaces for its abstractions, rather than generics, similar code isn't currently possible:
public interface IFoo {}
public interface IFactory
{
IFoo Create();
}
public class Foo : IFoo {}
public class FooFactory : IFactory
{
public Foo Create() => null; // Compiler complains at Foo; wants IFoo
}
Such code would become legal with covariant return types.
Covariant return types means that an method override can specify a more specific return type than the base method. Eg.
class WebRequest {
virtual WebRequest Create() { ... }
}
class HttpWebRequest : WebRequest {
override HttpWebRequest Create() { ... }
}
Currently (without covariant return types) the overriden method have to specify the exact same return type, WebRequest
, and you will have to manually cast the return value to HttpWebRequest
, which is ugly.
(Apologies beforehand, by C# is a bit rusty)
As mentioned in the other answers the big feature of convariant return types is that you can override virtual functions with functions that return a more specific return type.
For example:
public class Foo
{
virtual public Foo getCopy(); { //Create a copy of this Foo and return it }
}
The getCopy()
method returns a copy of the Foo
it is invoked on, so far, so good. Let's add a class that inherits from Foo
.
public class Bar : Foo
{
override public Foo getCopy(); { //Create a copy of this Bar and return it as a Foo }
}
Note that without covariant return types we need to declare that we return a Foo
(officially) instead of a Bar
(even though we actually return a Bar
). This might not be that bad until you write the following code.
//Copying things
Foo myFoo;
Foo myOtherFoo = myFoo.getCopy();
Bar myBar;
Bar myOtherBar = myBar.getCopy(); //Compiler error - getCopy() returns a Foo
Even though you know that myBar is a Bar
, and that you (actually) get a Bar
from the myBars's getCopy()
, you need to cast the return value to get it to compile. Worse, it is a potential source for bugs...
public class Baz : Foo
{
override public Foo getCopy(); { //Create a copy of this Baz and return it as a Foo }
}
//Copying more things
Foo myFoo;
Foo myOtherFoo = myFoo.getCopy();
Bar myBar;
Bar myOtherBar = myBar.getCopy() as Bar;
Baz myBaz;
Baz myOtherBaz = myBar.getCopy() as Baz; //Whoops
Notice the typo? Without covariant return values you might only notice during runtime (when the program crashes), with them the compiler can tell you at compile time: No, that can't work.
In summary: Covariant Return Values let you write shorter, preciser and safer code.