Questions tagged [covariance]

Covariance, contravariance and invariance describe how the existing type inheritance hierarchy changes when subjected to some transformation (such as usage within generics). If the transformation keeps the ordering of the original hierarchy, it is "covariant". If it reverses it, it is "contravariant". If it breaks it, it is "invariant".

About Type Ordering

Let's say that a class P (parent) is inherited by a class C (child).

We can denote this fact as: P > C.

Informally, P is "larger" than C since it "contains" all the possible instances of C, but can also contain some other instances that are not C. Child is always parent but not necessarily the other way around.

Variance in Generics

Let's say that there is a generic type G that has a single generic parameter T, denoted by: G{T}.

  • If G{P} > G{C}, then T is co-variant (it preserves the original inheritance ordering).
  • If G{P} < G{C}, then T is contra-variant (it reverses the original inheritance ordering).
  • If G{P} and G{C} are type-unrelated, then T is invariant (it "breaks" the inheritance).

So the variance is the property of transformation (in this case: generic parameter T of G), not the original type hierarchy (P and C).

C# Examples

The generic parameter T of IEnumerable<out T> is covariant (as denoted by "out" keyword), meaning you can "forget" that the collection contains Cs and just treat it as if it contains Ps. For example:

IEnumerable<C> ec = ...;
IEnumerable<P> ep = ec;

The generic parameter T of Action<in T> is contravariant (as denoted by "in" keyword), meaning that an action that accepts P can also accept C. For example:

Action<P> ap = ...;
Action<C> ac = ap;

The generic parameter T is contravariant and generic parameter TResult is covariant in Func<in T, out TResult>. Each generic parameter is considered a different "transformation" with its own variance. This lets you write a code like this:

Func<P, C> fpc = ...;
Func<C, P> fcp = fpc;

And finally, the generic parameter T of IList<T> is considered invariant, so IList<P> and IList<C> are considered unrelated types (there is no assignment compatibility in either direction).


Tag usage

  • Do not use for the measurement of the strength and direction of the linear relationship between two random variables (statistical context). Instead, use other related tags, for example, .
    Moreover, consider whether the question might be better suited to Cross Validated, the Stack Exchange site for statistics, machine learning and data analysis.
1905 questions
9
votes
2 answers

Why would making List.AddRange method a generic one be bad for performance?

I was reading C# in Depth (3rd edition) and in chapter 13, in a section which talks about inclusion of covariant and contravariant type parameters in c# 4, this claim is made: The parameter for List.AddRange is of type IEnumerable, so in this…
user1242967
  • 1,220
  • 3
  • 18
  • 30
9
votes
4 answers

Need clarification on the Rust Nomicon section on (co)variance of `Box`, `Vec` and other collections

The Rust Nomicon has an entire section on variance which I more or less understand except this little section in regards to Box and Vec being (co)variant over T. Box and Vec are interesting cases because they're variant, but you can…
L.Y. Sim
  • 810
  • 6
  • 11
9
votes
3 answers

How is covariance cooler than polymorphism...and not redundant?

.NET 4 introduces covariance. I guess it is useful. After all, MS went through all the trouble of adding it to the C# language. But, why is Covariance more useful than good old polymorphism? I wrote this example to understand why I should…
P.Brian.Mackey
  • 43,228
  • 68
  • 238
  • 348
9
votes
2 answers

I really don't understand this co/contravariance thing... I cannot have both generic get and set methods?

I think I'll explain my problems with some examples.. interface IModel {} class MyModel : IModel {} interface IRepo where T: IModel { } class Repo : IRepo { } // Cannot implicitly convert.. An explicit convertion exists. Missing…
simendsjo
  • 4,739
  • 2
  • 25
  • 53
9
votes
1 answer

Is there a way to determine the Variance of an Interface / Delegate in C# 4.0?

So now that we have generic Covariance and Contravariance on interfaces and delegates in C#, I was just curious if given a Type, you can figure out the covariance/contravariance of its generic arguments. I started trying to write my own…
BFree
  • 102,548
  • 21
  • 159
  • 201
9
votes
2 answers

Covariant return type and type conversion

s->duplicate() returns an object of type Box*, but I'm getting an error initializing it with Box*. It looks like it's being converted back to Shape*. What is the point of having covariant return types if it's converted back to the base class…
template boy
  • 10,230
  • 8
  • 61
  • 97
9
votes
3 answers

Workaround for lack of return type covariance when overriding virtual methods

is there any way to 'hack' or 'coerce' covariant overrides in to C#? For example: public class Alpha { public virtual Alpha DoSomething() { return AlphaFactory.GetAlphaFromSomewhere(); } } public class Beta : Alpha { public…
Xenoprimate
  • 7,691
  • 15
  • 58
  • 95
9
votes
1 answer

Why is covariance not allowed with ReadOnlyCollection?

The reason this code works is due to the fact that the Enumerator cannot modify the collection: var roList = new List() { "One", "Two", "Three" }; IEnumerable objEnum = roList; If we try to do the same thing with a List,…
B.K.
  • 9,982
  • 10
  • 73
  • 105
9
votes
1 answer

Internal Implementation of AsEnumerable() in LINQ

I have two questions: Question 1 Background : I noticed when looking at the implementation of 'AsEnumerable()' method in LINQ from Microsoft, which was: public static IEnumerable AsEnumerable(this IEnumerable source) { …
RaM
  • 1,126
  • 10
  • 25
9
votes
2 answers

Can a String[] hold System.Object inside it?

Do you feel question is strange? yes what happened also strange. let me explain. I have found a snippet from this Covariance and Contravariance with C# Arrays string[] strings = new string[1]; object[] objects = strings; objects[0] = new…
Sriram Sakthivel
  • 72,067
  • 7
  • 111
  • 189
9
votes
2 answers

How to use C# generics without wildcards?

Over in java I'm pretty used to working with generics and the wildcard. Things like: List. This allows you to have a collection of subtypes of Animals and run generic routines on each element (e.g. makeNoise()). I'm trying to…
John Newman
  • 113
  • 9
9
votes
6 answers

Generic constraint for Action doesn't work as expected

I am having some trouble understanding why the following snippet does not give me an error public void SomeMethod(T arg) where T : MyInterface { MyInterface e = arg; } But this one, which I would expect to work due to the generic type…
Jim Jeffries
  • 9,841
  • 15
  • 62
  • 103