How to Read to End Process Output Asynchronously in C#

C# Covariance on subclass return types

UPDATE: This answer was written in 2011. After two decades of people proposing return type covariance for C#, it looks like it will finally be implemented; I am rather surprised. See the bottom of https://devblogs.microsoft.com/dotnet/welcome-to-c-9-0/ for the announcement; I'm sure details will follow.


First off, return type contravariance doesn't make any sense; I think you are talking about return type covariance.

See this question for details:

Does C# support return type covariance?

You want to know why the feature is not implemented. phoog is correct; the feature is not implemented because no one here ever implemented it. A necessary but insufficient requirement is that the feature's benefits exceed its costs.

The costs are considerable. The feature is not supported natively by the runtime, it works directly against our goal to make C# versionable because it introduces yet another form of the brittle base class problem, Anders doesn't think it is an interesting or useful feature, and if you really want it, you can make it work by writing little helper methods. (Which is exactly what the CIL version of C++ does.)

The benefits are small.

High cost, small benefit features with an easy workaround get triaged away very quickly. We have far higher priorities.

Does C# support return type covariance?


UPDATE: This answer was written in 2011. After two decades of people proposing return type covariance for C# they have been implemented. See Covariant Returns in https://devblogs.microsoft.com/dotnet/c-9-0-on-the-record/.


It sounds like what you want is return type covariance. C# does not support return type covariance.

Return type covariance is where you override a base class method that returns a less-specific type with one that returns a more specific type:

abstract class Enclosure
{
public abstract Animal Contents();
}
class Aquarium : Enclosure
{
public override Fish Contents() { ... }
}

This is safe because consumers of Contents via Enclosure expect an Animal, and Aquarium promises to not only fulfill that requirement, but moreover, to make a more strict promise: that the animal is always a fish.

This kind of covariance is not supported in C#, and is unlikely to ever be supported. It is not supported by the CLR. (It is supported by C++, and by the C++/CLI implementation on the CLR; it does so by generating magical helper methods of the sort I suggest below.)

(Some languages support formal parameter type contravariance as well -- that you can override a method that takes a Fish with a method that takes an Animal. Again, the contract is fulfilled; the base class requires that any Fish be handled, and the derived class promises to not only handle fish, but any animal. Similarly, C# and the CLR do not support formal parameter type contravariance.)

The way you can work around this limitation is to do something like:

abstract class Enclosure
{
protected abstract Animal GetContents();
public Animal Contents() { return this.GetContents(); }
}
class Aquarium : Enclosure
{
protected override Animal GetContents() { return this.Contents(); }
public new Fish Contents() { ... }
}

Now you get both the benefits of overriding a virtual method, and getting stronger typing when using something of compile-time type Aquarium.

Workaround for lack of return type covariance when overriding virtual methods

You can do some pretty zany stuff with generics.

public class Alpha<T> where T: Alpha<T> {
public virtual T DoSomething() {
throw new NotImplementedException();
}
}
public class Beta : Alpha<Beta> {
public override Beta DoSomething() {
throw new NotImplementedException();
}
}

c# covariant return types utilizing generics

UPDATE: This answer was written in 2010. After two decades of people proposing return type covariance for C#, it looks like it will finally be implemented; I am rather surprised. See the bottom of https://devblogs.microsoft.com/dotnet/welcome-to-c-9-0/ for the announcement; I'm sure details will follow. The portions of the answer below which speculate on the possibility of the feature being implemented should be considered of historical interest only going forwards.


First off, the answer to your question is no, C# does not support any form of return type covariance on virtual overrides.

A number of answerers and commenters have said "there is no covariance in this question". This is incorrect; the original poster was entirely correct to pose the question as they did.

Recall that a covariant mapping is a mapping which preserves the existence and direction of some other relation. For example, the mapping from a type T to a type IEnumerable<T> is covariant because it preserves the assignment compatibility relation. If Tiger is assignment compatible with Animal, then the transformation under the map is also preserved: IEnumerable<Tiger> is assignment compatible with IEnumerable<Animal>.

The covariant mapping here is a little bit harder to see, but it is still there. The question essentially is this: should this be legal?

class B
{
public virtual Animal M() {...}
}
class D : B
{
public override Tiger M() {...}
}

Tiger is assignment-compatible with Animal. Now make a mapping from a type T to a method "public T M()". Does that mapping preserve compatibility? That is, if Tiger is compatible with Animal for the purposes of assignment, then is public Tiger M() compatible with public Animal M() for the purposes of virtual overriding?

The answer in C# is "no". C# does not support this kind of covariance.

Now that we have established that the question has been asked using the correct type algebra jargon, a few more thoughts on the actual question. The obvious first problem is that the property has not even been declared as virtual, so questions of virtual compatibilty are moot. The obvious second problem is that a "get; set;" property could not be covariant even if C# did support return type covariance because the type of a property with a setter is not just its return type, it is also its formal parameter type. You need contravariance on formal parameter types to achieve type safety. If we allowed return type covariance on properties with setters then you'd have:

class B
{
public virtual Animal Animal{ get; set;}
}
class D : B
{
public override Tiger Animal { ... }
}

B b = new D();
b.Animal = new Giraffe();

and hey, we just passed a Giraffe to a setter that is expecting a Tiger. If we supported this feature we would have to restrict it to return types (as we do with assignment-compatibility covariance on generic interfaces.)

The third problem is that the CLR does not support this kind of variance; if we wanted to support it in the language (as I believe managed C++ does) then we would have to do some reasonably heroic measures to work around signature matching restrictions in the CLR.

You can do those heroic measures yourself by carefully defining "new" methods that have the appropriate return types that shadow their base class types:

abstract class B 
{
protected abstract Animal ProtectedM();
public Animal Animal { get { return this.ProtectedM(); } }
}
class D : B
{
protected override Animal ProtectedM() { return new Tiger(); }
public new Tiger Animal { get { return (Tiger)this.ProtectedM(); } }
}

Now if you have an instance of D, you see the Tiger-typed property. If you cast it to B then you see the Animal-typed property. In either case, you still get the virtual behaviour via the protected member.

In short, we have no plans to ever do this feature, sorry.

subtype and covariant return type

Unlike java, covariant return types are not supported in C#. I believe this is due to the implementation of C# properties, if covariant return types were allowed, the following would be possible:

class TypeX { }

class TypeY : TypeX { }

class Base
{
public virtual TypeX Prop { get; set; }
}

class Derived : Base
{
public override TypeY Prop { get; set; }
}

Derived derived = new Derived();
derived.Prop = new TypeY(); // Valid

Base @base = derived;
@base.Prop = new TypeX(); // Invalid - As this would be using the derived property which should be of TypeY

See Eric Lippert's answer for more information.

Problem with Covariant return types from an abstract method

Justin I am a little bit confused why you need to go through all that trouble.

If you abstract method is of return type IQueryable<CandidateBase> then that's what you'll get. I don't see a problem with this, since later on you could still cast it back to CandidateA or CandidateB

So what exactly are you trying to achieve? Maybe I am not understanding you question.

Edit to add:

Justin, what about this?

public abstract class RecruiterBase<T>
{
// Constructors declared here

public abstract IQueryable<CandidateBase> GetCandidates();
}

public abstract class CandidateBase
{
// Constructors declared here
}

public class CandidateA : CandidateBase
{

}

public class RecruiterA : RecruiterBase<RecruiterA>
{
// Constructors declared here

// ----HERE IS WHERE I AM BREAKING DOWN----
public override IQueryable<CandidateBase> GetCandidates()
{
return db.Candidates.Where(cand => cand.RecruiterId == this.RecruiterId)
.Select(x => new CandidateA
{
CandidateId = c.CandidateId,
CandidateName = c.CandidateName,
RecruiterId = c.RecruiterId
})
.Cast<CandidateBase>()
.AsQueryable();
}
}

How to use covariant return types with lists in interface methods?

This does not compile.

You have two options:

  • Try List<? extends Player> getPlayers() in your interface, and now you can write List<EspnPlayer> getPlayers() which is a valid implementation if this. Note that it is not possible to call .add() on this list, for proper reasons (after all, adding a non-EspnPlayer to this list would break the list!)
  • If that add thing is required, then there's no way out except to have:
interface NbaService<T extends Player> {
public List<T> getPlayers();
}


In Object Oriented Programming, "programming to an interface" is often considered a best practice.

Nice use of the passive voice there, but, as wikipedia editors would say, [citation needed].

There is a grain of truth to this, but as with all programming style suggestions, it's oversimplified. Which isn't a problem, but that's why the following maxim is pretty much always true: If you don't understand the reasons behind a style recommendation, then blindly following it is stupid and will result in worse code. There is no easy out: You must first grok the considerations underlying the recommendation, and until then you just cannot use the recommendation.

Covariance with C# Generics

The fact that AMQuestion implements the IQuestion interface does not translate into List<AMQuestion> deriving from List<IQuestion>.

Because this cast is illegal, your as operator returns null.

You must cast each item individually as such:

IList<IQuestion> nonTyped = typed.Cast<IQuestion>().ToList();

Regarding your comment, consider the following code, with the usual cliché animal examples:

//Lizard and Donkey inherit from Animal
List<Lizard> lizards = new List<Lizard> { new Lizard() };
List<Donkey> donkeys = new List<Donkey> { new Donkey() };

List<Animal> animals = lizards as List<Animal>; //let's pretend this doesn't return null
animals.Add(new Donkey()); //Reality unravels!

if we were allowed to cast List<Lizard> to a List<Animal>, then we could theoretically add a new Donkey to that list, which would break inheritance.

covariance in c#

You can't do this, because it wouldn't be safe. Consider:

List<Joe> joes = GetJoes();    
List<Human> humanJoes = joes;
humanJoes.Clear();
humanJoes.Add(new Fred());
Joe joe = joes[0];

Clearly the last line (if not an earlier one) has to fail - as a Fred isn't a Joe. The invariance of List<T> prevents this mistake at compile time instead of execution time.

What is a covariant return type?

Covariant return, means that when one overrides a method, the return type of the overriding method is allowed to be a subtype of the overridden method's return type.

To clarify this with an example, a common case is Object.clone() - which is declared to return a type of Object. You could override this in your own class as follows:

public class MyFoo
{

...

// Note covariant return here, method does not just return Object
public MyFoo clone()
{
// Implementation
}
}

The benefit here is that any method which holds an explicit reference to a MyFoo object will be able to invoke clone() and know (without casting) that the return value is an instance of MyFoo. Without covariant return types, the overridden method in MyFoo would have to be declared to return Object - and so calling code would have to explicitly downcast the result of the method call (even thought both sides "know" it can only ever be an instance of MyFoo).

Note that there's nothing special about clone() and that any overridden method can have a covariant return - I used it as an example here as it's a standard method where this is often useful.



Related Topics



Leave a reply



Submit