Understanding Covariant and Contravariant interfaces in C#











up vote
79
down vote

favorite
46












I've come across these in a textbook I am reading on C#, but I am having difficulty understanding them, probably due to lack of context.



Is there a good concise explanation of what they are and what they are useful for out there?



Edit for clarification:



Covariant interface:



interface IBibble<out T>
.
.


Contravariant interface:



interface IBibble<in T>
.
.









share|improve this question




















  • 3




    This is a short and good expalnation IMHO: blogs.msdn.com/csharpfaq/archive/2010/02/16/…
    – digEmAll
    Apr 27 '10 at 9:16










  • May be useful: Blog Post
    – Krunal
    Apr 27 '10 at 9:19










  • Hmm it is good but it doesn't explain why which is what is really baffling me.
    – NibblyPig
    Apr 27 '10 at 9:29















up vote
79
down vote

favorite
46












I've come across these in a textbook I am reading on C#, but I am having difficulty understanding them, probably due to lack of context.



Is there a good concise explanation of what they are and what they are useful for out there?



Edit for clarification:



Covariant interface:



interface IBibble<out T>
.
.


Contravariant interface:



interface IBibble<in T>
.
.









share|improve this question




















  • 3




    This is a short and good expalnation IMHO: blogs.msdn.com/csharpfaq/archive/2010/02/16/…
    – digEmAll
    Apr 27 '10 at 9:16










  • May be useful: Blog Post
    – Krunal
    Apr 27 '10 at 9:19










  • Hmm it is good but it doesn't explain why which is what is really baffling me.
    – NibblyPig
    Apr 27 '10 at 9:29













up vote
79
down vote

favorite
46









up vote
79
down vote

favorite
46






46





I've come across these in a textbook I am reading on C#, but I am having difficulty understanding them, probably due to lack of context.



Is there a good concise explanation of what they are and what they are useful for out there?



Edit for clarification:



Covariant interface:



interface IBibble<out T>
.
.


Contravariant interface:



interface IBibble<in T>
.
.









share|improve this question















I've come across these in a textbook I am reading on C#, but I am having difficulty understanding them, probably due to lack of context.



Is there a good concise explanation of what they are and what they are useful for out there?



Edit for clarification:



Covariant interface:



interface IBibble<out T>
.
.


Contravariant interface:



interface IBibble<in T>
.
.






c# .net interface covariance contravariance






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Jul 27 '15 at 9:17









Henk Holterman

207k22226397




207k22226397










asked Apr 27 '10 at 9:13









NibblyPig

24k58149276




24k58149276








  • 3




    This is a short and good expalnation IMHO: blogs.msdn.com/csharpfaq/archive/2010/02/16/…
    – digEmAll
    Apr 27 '10 at 9:16










  • May be useful: Blog Post
    – Krunal
    Apr 27 '10 at 9:19










  • Hmm it is good but it doesn't explain why which is what is really baffling me.
    – NibblyPig
    Apr 27 '10 at 9:29














  • 3




    This is a short and good expalnation IMHO: blogs.msdn.com/csharpfaq/archive/2010/02/16/…
    – digEmAll
    Apr 27 '10 at 9:16










  • May be useful: Blog Post
    – Krunal
    Apr 27 '10 at 9:19










  • Hmm it is good but it doesn't explain why which is what is really baffling me.
    – NibblyPig
    Apr 27 '10 at 9:29








3




3




This is a short and good expalnation IMHO: blogs.msdn.com/csharpfaq/archive/2010/02/16/…
– digEmAll
Apr 27 '10 at 9:16




This is a short and good expalnation IMHO: blogs.msdn.com/csharpfaq/archive/2010/02/16/…
– digEmAll
Apr 27 '10 at 9:16












May be useful: Blog Post
– Krunal
Apr 27 '10 at 9:19




May be useful: Blog Post
– Krunal
Apr 27 '10 at 9:19












Hmm it is good but it doesn't explain why which is what is really baffling me.
– NibblyPig
Apr 27 '10 at 9:29




Hmm it is good but it doesn't explain why which is what is really baffling me.
– NibblyPig
Apr 27 '10 at 9:29












2 Answers
2






active

oldest

votes

















up vote
121
down vote



accepted










With <out T>, you can treat the interface reference as one upwards in the hierarchy.



With <in T>, you can treat the interface reference as one downwards in the hiearchy.



Let me try to explain it in more english terms.



Let's say you are retrieving a list of animals from your zoo, and you intend to process them. All animals (in your zoo) have a name, and a unique ID. Some animals are mammals, some are reptiles, some are amphibians, some are fish, etc. but they're all animals.



So, with your list of animals (which contains animals of different types), you can say that all the animals have a name, so obviously it would be safe to get the name of all the animals.



However, what if you have a list of fishes only, but need to treat them like animals, does that work? Intuitively, it should work, but in C# 3.0 and before, this piece of code will not compile:



IEnumerable<Animal> animals = GetFishes(); // returns IEnumerable<Fish>


The reason for this is that the compiler doesn't "know" what you intend, or can, do with the animals collection after you've retrieved it. For all it knows, there could be a way through IEnumerable<T> to put an object back into the list, and that would potentially allow you to put an animal that isn't a fish, into a collection that is supposed to contain only fish.



In other words, the compiler cannot guarantee that this is not allowed:



animals.Add(new Mammal("Zebra"));


So the compiler just outright refuses to compile your code. This is covariance.



Let's look at contravariance.



Since our zoo can handle all animals, it can certainly handle fish, so let's try to add some fish to our zoo.



In C# 3.0 and before, this does not compile:



List<Fish> fishes = GetAccessToFishes(); // for some reason, returns List<Animal>
fishes.Add(new Fish("Guppy"));


Here, the compiler could allow this piece of code, even though the method returns List<Animal> simply because all fishes are animals, so if we just changed the types to this:



List<Animal> fishes = GetAccessToFishes();
fishes.Add(new Fish("Guppy"));


Then it would work, but the compiler cannot determine that you're not trying to do this:



List<Fish> fishes = GetAccessToFishes(); // for some reason, returns List<Animal>
Fish firstFist = fishes[0];


Since the list is actually a list of animals, this is not allowed.



So contra- and co-variance is how you treat object references and what you're allowed to do with them.



The in and out keywords in C# 4.0 specifically marks the interface as one or the other. With in, you're allowed to place the generic type (usually T) in input-positions, which means method arguments, and write-only properties.



With out, you're allowed to place the generic type in output-positions, which is method return values, read-only properties, and out method parameters.



This will allow you to do what intended to do with the code:



IEnumerable<Animal> animals = GetFishes(); // returns IEnumerable<Fish>
// since we can only get animals *out* of the collection, every fish is an animal
// so this is safe


List<T> has both in- and out-directions on T, so it is neither co-variant nor contra-variant, but an interface that allowed you to add objects, like this:



interface IWriteOnlyList<in T>
{
void Add(T value);
}


would allow you to do this:



IWriteOnlyList<Fish> fishes = GetWriteAccessToAnimals(); // still returns
IWriteOnlyList<Animal>
fishes.Add(new Fish("Guppy")); <-- this is now safe




Here's a few videos that shows the concepts:




  • Covariance and Contravariance - VS2010 C# Part 1 of 3

  • Covariance and Contravariance - VS2010 C# Part 2 of 3

  • Covariance and Contravariance - VS2010 C# Part 3 of 3


Here's an example:



namespace SO2719954
{
class Base { }
class Descendant : Base { }

interface IBibbleOut<out T> { }
interface IBibbleIn<in T> { }

class Program
{
static void Main(string args)
{
// We can do this since every Descendant is also a Base
// and there is no chance we can put Base objects into
// the returned object, since T is "out"
// We can not, however, put Base objects into b, since all
// Base objects might not be Descendant.
IBibbleOut<Base> b = GetOutDescendant();

// We can do this since every Descendant is also a Base
// and we can now put Descendant objects into Base
// We can not, however, retrieve Descendant objects out
// of d, since all Base objects might not be Descendant
IBibbleIn<Descendant> d = GetInBase();
}

static IBibbleOut<Descendant> GetOutDescendant()
{
return null;
}

static IBibbleIn<Base> GetInBase()
{
return null;
}
}
}


Without these marks, the following could compile:



public List<Descendant> GetDescendants() ...
List<Base> bases = GetDescendants();
bases.Add(new Base()); <-- uh-oh, we try to add a Base to a Descendant


or this:



public List<Base> GetBases() ...
List<Descendant> descendants = GetBases(); <-- uh-oh, we try to treat all Bases
as Descendants





share|improve this answer























  • Hmm, would you be able to explain the goal of covariance and contravariance? It might help me to understand it more.
    – NibblyPig
    Apr 27 '10 at 9:34






  • 1




    See the last bit, which is what the compiler prevented before, the purpose of in and out is to say what you can do with the interfaces (or types) that is safe, so that the compiler won't prevent you from doing safe things.
    – Lasse Vågsæther Karlsen
    Apr 27 '10 at 9:54










  • Superb answer, I watched the videos they were very helpful, and combined with your example I have it sorted now. Only one question remains, and that is why are 'out' and 'in' required, why doesn't visual studio automatically know what you are trying to do (or whats the reason behind it)?
    – NibblyPig
    Apr 27 '10 at 10:19










  • Automagic "I see what you're trying to do there" is usually frowned upon when it comes to declaring stuff like classes, it is better to have the programmer explicitly mark the types. You can try adding "in" to a class that has methods that return T and the compiler will complain. Imagine what would happen if it silently just removed the "in" it had previously automatically added for you.
    – Lasse Vågsæther Karlsen
    Apr 27 '10 at 10:27






  • 1




    If one keyword needs this long explanation, something is clearly wrong. In my opinion, C# is trying to be too smart in this particular case. Nonetheless, thank you for cool explanation.
    – rr-
    Jun 5 '14 at 6:58


















up vote
5
down vote













This post is the best I've read on the subject



In short, covariance / contravariance /invariance deals with automatic type casting (from base to derived and vice-versa). Those type casts are possible only if some guarantees are respected in terms of read / write actions performed on the casted objects.
Read the post for more details.






share|improve this answer























  • very good article indeed. :) thanks
    – gsimoes
    May 24 '16 at 0:48






  • 5




    Link appears dead. Here's an archived version: web.archive.org/web/20140626123445/http://adamnathan.co.uk/…
    – si618
    Aug 23 '16 at 7:32













Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f2719954%2funderstanding-covariant-and-contravariant-interfaces-in-c-sharp%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























2 Answers
2






active

oldest

votes








2 Answers
2






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
121
down vote



accepted










With <out T>, you can treat the interface reference as one upwards in the hierarchy.



With <in T>, you can treat the interface reference as one downwards in the hiearchy.



Let me try to explain it in more english terms.



Let's say you are retrieving a list of animals from your zoo, and you intend to process them. All animals (in your zoo) have a name, and a unique ID. Some animals are mammals, some are reptiles, some are amphibians, some are fish, etc. but they're all animals.



So, with your list of animals (which contains animals of different types), you can say that all the animals have a name, so obviously it would be safe to get the name of all the animals.



However, what if you have a list of fishes only, but need to treat them like animals, does that work? Intuitively, it should work, but in C# 3.0 and before, this piece of code will not compile:



IEnumerable<Animal> animals = GetFishes(); // returns IEnumerable<Fish>


The reason for this is that the compiler doesn't "know" what you intend, or can, do with the animals collection after you've retrieved it. For all it knows, there could be a way through IEnumerable<T> to put an object back into the list, and that would potentially allow you to put an animal that isn't a fish, into a collection that is supposed to contain only fish.



In other words, the compiler cannot guarantee that this is not allowed:



animals.Add(new Mammal("Zebra"));


So the compiler just outright refuses to compile your code. This is covariance.



Let's look at contravariance.



Since our zoo can handle all animals, it can certainly handle fish, so let's try to add some fish to our zoo.



In C# 3.0 and before, this does not compile:



List<Fish> fishes = GetAccessToFishes(); // for some reason, returns List<Animal>
fishes.Add(new Fish("Guppy"));


Here, the compiler could allow this piece of code, even though the method returns List<Animal> simply because all fishes are animals, so if we just changed the types to this:



List<Animal> fishes = GetAccessToFishes();
fishes.Add(new Fish("Guppy"));


Then it would work, but the compiler cannot determine that you're not trying to do this:



List<Fish> fishes = GetAccessToFishes(); // for some reason, returns List<Animal>
Fish firstFist = fishes[0];


Since the list is actually a list of animals, this is not allowed.



So contra- and co-variance is how you treat object references and what you're allowed to do with them.



The in and out keywords in C# 4.0 specifically marks the interface as one or the other. With in, you're allowed to place the generic type (usually T) in input-positions, which means method arguments, and write-only properties.



With out, you're allowed to place the generic type in output-positions, which is method return values, read-only properties, and out method parameters.



This will allow you to do what intended to do with the code:



IEnumerable<Animal> animals = GetFishes(); // returns IEnumerable<Fish>
// since we can only get animals *out* of the collection, every fish is an animal
// so this is safe


List<T> has both in- and out-directions on T, so it is neither co-variant nor contra-variant, but an interface that allowed you to add objects, like this:



interface IWriteOnlyList<in T>
{
void Add(T value);
}


would allow you to do this:



IWriteOnlyList<Fish> fishes = GetWriteAccessToAnimals(); // still returns
IWriteOnlyList<Animal>
fishes.Add(new Fish("Guppy")); <-- this is now safe




Here's a few videos that shows the concepts:




  • Covariance and Contravariance - VS2010 C# Part 1 of 3

  • Covariance and Contravariance - VS2010 C# Part 2 of 3

  • Covariance and Contravariance - VS2010 C# Part 3 of 3


Here's an example:



namespace SO2719954
{
class Base { }
class Descendant : Base { }

interface IBibbleOut<out T> { }
interface IBibbleIn<in T> { }

class Program
{
static void Main(string args)
{
// We can do this since every Descendant is also a Base
// and there is no chance we can put Base objects into
// the returned object, since T is "out"
// We can not, however, put Base objects into b, since all
// Base objects might not be Descendant.
IBibbleOut<Base> b = GetOutDescendant();

// We can do this since every Descendant is also a Base
// and we can now put Descendant objects into Base
// We can not, however, retrieve Descendant objects out
// of d, since all Base objects might not be Descendant
IBibbleIn<Descendant> d = GetInBase();
}

static IBibbleOut<Descendant> GetOutDescendant()
{
return null;
}

static IBibbleIn<Base> GetInBase()
{
return null;
}
}
}


Without these marks, the following could compile:



public List<Descendant> GetDescendants() ...
List<Base> bases = GetDescendants();
bases.Add(new Base()); <-- uh-oh, we try to add a Base to a Descendant


or this:



public List<Base> GetBases() ...
List<Descendant> descendants = GetBases(); <-- uh-oh, we try to treat all Bases
as Descendants





share|improve this answer























  • Hmm, would you be able to explain the goal of covariance and contravariance? It might help me to understand it more.
    – NibblyPig
    Apr 27 '10 at 9:34






  • 1




    See the last bit, which is what the compiler prevented before, the purpose of in and out is to say what you can do with the interfaces (or types) that is safe, so that the compiler won't prevent you from doing safe things.
    – Lasse Vågsæther Karlsen
    Apr 27 '10 at 9:54










  • Superb answer, I watched the videos they were very helpful, and combined with your example I have it sorted now. Only one question remains, and that is why are 'out' and 'in' required, why doesn't visual studio automatically know what you are trying to do (or whats the reason behind it)?
    – NibblyPig
    Apr 27 '10 at 10:19










  • Automagic "I see what you're trying to do there" is usually frowned upon when it comes to declaring stuff like classes, it is better to have the programmer explicitly mark the types. You can try adding "in" to a class that has methods that return T and the compiler will complain. Imagine what would happen if it silently just removed the "in" it had previously automatically added for you.
    – Lasse Vågsæther Karlsen
    Apr 27 '10 at 10:27






  • 1




    If one keyword needs this long explanation, something is clearly wrong. In my opinion, C# is trying to be too smart in this particular case. Nonetheless, thank you for cool explanation.
    – rr-
    Jun 5 '14 at 6:58















up vote
121
down vote



accepted










With <out T>, you can treat the interface reference as one upwards in the hierarchy.



With <in T>, you can treat the interface reference as one downwards in the hiearchy.



Let me try to explain it in more english terms.



Let's say you are retrieving a list of animals from your zoo, and you intend to process them. All animals (in your zoo) have a name, and a unique ID. Some animals are mammals, some are reptiles, some are amphibians, some are fish, etc. but they're all animals.



So, with your list of animals (which contains animals of different types), you can say that all the animals have a name, so obviously it would be safe to get the name of all the animals.



However, what if you have a list of fishes only, but need to treat them like animals, does that work? Intuitively, it should work, but in C# 3.0 and before, this piece of code will not compile:



IEnumerable<Animal> animals = GetFishes(); // returns IEnumerable<Fish>


The reason for this is that the compiler doesn't "know" what you intend, or can, do with the animals collection after you've retrieved it. For all it knows, there could be a way through IEnumerable<T> to put an object back into the list, and that would potentially allow you to put an animal that isn't a fish, into a collection that is supposed to contain only fish.



In other words, the compiler cannot guarantee that this is not allowed:



animals.Add(new Mammal("Zebra"));


So the compiler just outright refuses to compile your code. This is covariance.



Let's look at contravariance.



Since our zoo can handle all animals, it can certainly handle fish, so let's try to add some fish to our zoo.



In C# 3.0 and before, this does not compile:



List<Fish> fishes = GetAccessToFishes(); // for some reason, returns List<Animal>
fishes.Add(new Fish("Guppy"));


Here, the compiler could allow this piece of code, even though the method returns List<Animal> simply because all fishes are animals, so if we just changed the types to this:



List<Animal> fishes = GetAccessToFishes();
fishes.Add(new Fish("Guppy"));


Then it would work, but the compiler cannot determine that you're not trying to do this:



List<Fish> fishes = GetAccessToFishes(); // for some reason, returns List<Animal>
Fish firstFist = fishes[0];


Since the list is actually a list of animals, this is not allowed.



So contra- and co-variance is how you treat object references and what you're allowed to do with them.



The in and out keywords in C# 4.0 specifically marks the interface as one or the other. With in, you're allowed to place the generic type (usually T) in input-positions, which means method arguments, and write-only properties.



With out, you're allowed to place the generic type in output-positions, which is method return values, read-only properties, and out method parameters.



This will allow you to do what intended to do with the code:



IEnumerable<Animal> animals = GetFishes(); // returns IEnumerable<Fish>
// since we can only get animals *out* of the collection, every fish is an animal
// so this is safe


List<T> has both in- and out-directions on T, so it is neither co-variant nor contra-variant, but an interface that allowed you to add objects, like this:



interface IWriteOnlyList<in T>
{
void Add(T value);
}


would allow you to do this:



IWriteOnlyList<Fish> fishes = GetWriteAccessToAnimals(); // still returns
IWriteOnlyList<Animal>
fishes.Add(new Fish("Guppy")); <-- this is now safe




Here's a few videos that shows the concepts:




  • Covariance and Contravariance - VS2010 C# Part 1 of 3

  • Covariance and Contravariance - VS2010 C# Part 2 of 3

  • Covariance and Contravariance - VS2010 C# Part 3 of 3


Here's an example:



namespace SO2719954
{
class Base { }
class Descendant : Base { }

interface IBibbleOut<out T> { }
interface IBibbleIn<in T> { }

class Program
{
static void Main(string args)
{
// We can do this since every Descendant is also a Base
// and there is no chance we can put Base objects into
// the returned object, since T is "out"
// We can not, however, put Base objects into b, since all
// Base objects might not be Descendant.
IBibbleOut<Base> b = GetOutDescendant();

// We can do this since every Descendant is also a Base
// and we can now put Descendant objects into Base
// We can not, however, retrieve Descendant objects out
// of d, since all Base objects might not be Descendant
IBibbleIn<Descendant> d = GetInBase();
}

static IBibbleOut<Descendant> GetOutDescendant()
{
return null;
}

static IBibbleIn<Base> GetInBase()
{
return null;
}
}
}


Without these marks, the following could compile:



public List<Descendant> GetDescendants() ...
List<Base> bases = GetDescendants();
bases.Add(new Base()); <-- uh-oh, we try to add a Base to a Descendant


or this:



public List<Base> GetBases() ...
List<Descendant> descendants = GetBases(); <-- uh-oh, we try to treat all Bases
as Descendants





share|improve this answer























  • Hmm, would you be able to explain the goal of covariance and contravariance? It might help me to understand it more.
    – NibblyPig
    Apr 27 '10 at 9:34






  • 1




    See the last bit, which is what the compiler prevented before, the purpose of in and out is to say what you can do with the interfaces (or types) that is safe, so that the compiler won't prevent you from doing safe things.
    – Lasse Vågsæther Karlsen
    Apr 27 '10 at 9:54










  • Superb answer, I watched the videos they were very helpful, and combined with your example I have it sorted now. Only one question remains, and that is why are 'out' and 'in' required, why doesn't visual studio automatically know what you are trying to do (or whats the reason behind it)?
    – NibblyPig
    Apr 27 '10 at 10:19










  • Automagic "I see what you're trying to do there" is usually frowned upon when it comes to declaring stuff like classes, it is better to have the programmer explicitly mark the types. You can try adding "in" to a class that has methods that return T and the compiler will complain. Imagine what would happen if it silently just removed the "in" it had previously automatically added for you.
    – Lasse Vågsæther Karlsen
    Apr 27 '10 at 10:27






  • 1




    If one keyword needs this long explanation, something is clearly wrong. In my opinion, C# is trying to be too smart in this particular case. Nonetheless, thank you for cool explanation.
    – rr-
    Jun 5 '14 at 6:58













up vote
121
down vote



accepted







up vote
121
down vote



accepted






With <out T>, you can treat the interface reference as one upwards in the hierarchy.



With <in T>, you can treat the interface reference as one downwards in the hiearchy.



Let me try to explain it in more english terms.



Let's say you are retrieving a list of animals from your zoo, and you intend to process them. All animals (in your zoo) have a name, and a unique ID. Some animals are mammals, some are reptiles, some are amphibians, some are fish, etc. but they're all animals.



So, with your list of animals (which contains animals of different types), you can say that all the animals have a name, so obviously it would be safe to get the name of all the animals.



However, what if you have a list of fishes only, but need to treat them like animals, does that work? Intuitively, it should work, but in C# 3.0 and before, this piece of code will not compile:



IEnumerable<Animal> animals = GetFishes(); // returns IEnumerable<Fish>


The reason for this is that the compiler doesn't "know" what you intend, or can, do with the animals collection after you've retrieved it. For all it knows, there could be a way through IEnumerable<T> to put an object back into the list, and that would potentially allow you to put an animal that isn't a fish, into a collection that is supposed to contain only fish.



In other words, the compiler cannot guarantee that this is not allowed:



animals.Add(new Mammal("Zebra"));


So the compiler just outright refuses to compile your code. This is covariance.



Let's look at contravariance.



Since our zoo can handle all animals, it can certainly handle fish, so let's try to add some fish to our zoo.



In C# 3.0 and before, this does not compile:



List<Fish> fishes = GetAccessToFishes(); // for some reason, returns List<Animal>
fishes.Add(new Fish("Guppy"));


Here, the compiler could allow this piece of code, even though the method returns List<Animal> simply because all fishes are animals, so if we just changed the types to this:



List<Animal> fishes = GetAccessToFishes();
fishes.Add(new Fish("Guppy"));


Then it would work, but the compiler cannot determine that you're not trying to do this:



List<Fish> fishes = GetAccessToFishes(); // for some reason, returns List<Animal>
Fish firstFist = fishes[0];


Since the list is actually a list of animals, this is not allowed.



So contra- and co-variance is how you treat object references and what you're allowed to do with them.



The in and out keywords in C# 4.0 specifically marks the interface as one or the other. With in, you're allowed to place the generic type (usually T) in input-positions, which means method arguments, and write-only properties.



With out, you're allowed to place the generic type in output-positions, which is method return values, read-only properties, and out method parameters.



This will allow you to do what intended to do with the code:



IEnumerable<Animal> animals = GetFishes(); // returns IEnumerable<Fish>
// since we can only get animals *out* of the collection, every fish is an animal
// so this is safe


List<T> has both in- and out-directions on T, so it is neither co-variant nor contra-variant, but an interface that allowed you to add objects, like this:



interface IWriteOnlyList<in T>
{
void Add(T value);
}


would allow you to do this:



IWriteOnlyList<Fish> fishes = GetWriteAccessToAnimals(); // still returns
IWriteOnlyList<Animal>
fishes.Add(new Fish("Guppy")); <-- this is now safe




Here's a few videos that shows the concepts:




  • Covariance and Contravariance - VS2010 C# Part 1 of 3

  • Covariance and Contravariance - VS2010 C# Part 2 of 3

  • Covariance and Contravariance - VS2010 C# Part 3 of 3


Here's an example:



namespace SO2719954
{
class Base { }
class Descendant : Base { }

interface IBibbleOut<out T> { }
interface IBibbleIn<in T> { }

class Program
{
static void Main(string args)
{
// We can do this since every Descendant is also a Base
// and there is no chance we can put Base objects into
// the returned object, since T is "out"
// We can not, however, put Base objects into b, since all
// Base objects might not be Descendant.
IBibbleOut<Base> b = GetOutDescendant();

// We can do this since every Descendant is also a Base
// and we can now put Descendant objects into Base
// We can not, however, retrieve Descendant objects out
// of d, since all Base objects might not be Descendant
IBibbleIn<Descendant> d = GetInBase();
}

static IBibbleOut<Descendant> GetOutDescendant()
{
return null;
}

static IBibbleIn<Base> GetInBase()
{
return null;
}
}
}


Without these marks, the following could compile:



public List<Descendant> GetDescendants() ...
List<Base> bases = GetDescendants();
bases.Add(new Base()); <-- uh-oh, we try to add a Base to a Descendant


or this:



public List<Base> GetBases() ...
List<Descendant> descendants = GetBases(); <-- uh-oh, we try to treat all Bases
as Descendants





share|improve this answer














With <out T>, you can treat the interface reference as one upwards in the hierarchy.



With <in T>, you can treat the interface reference as one downwards in the hiearchy.



Let me try to explain it in more english terms.



Let's say you are retrieving a list of animals from your zoo, and you intend to process them. All animals (in your zoo) have a name, and a unique ID. Some animals are mammals, some are reptiles, some are amphibians, some are fish, etc. but they're all animals.



So, with your list of animals (which contains animals of different types), you can say that all the animals have a name, so obviously it would be safe to get the name of all the animals.



However, what if you have a list of fishes only, but need to treat them like animals, does that work? Intuitively, it should work, but in C# 3.0 and before, this piece of code will not compile:



IEnumerable<Animal> animals = GetFishes(); // returns IEnumerable<Fish>


The reason for this is that the compiler doesn't "know" what you intend, or can, do with the animals collection after you've retrieved it. For all it knows, there could be a way through IEnumerable<T> to put an object back into the list, and that would potentially allow you to put an animal that isn't a fish, into a collection that is supposed to contain only fish.



In other words, the compiler cannot guarantee that this is not allowed:



animals.Add(new Mammal("Zebra"));


So the compiler just outright refuses to compile your code. This is covariance.



Let's look at contravariance.



Since our zoo can handle all animals, it can certainly handle fish, so let's try to add some fish to our zoo.



In C# 3.0 and before, this does not compile:



List<Fish> fishes = GetAccessToFishes(); // for some reason, returns List<Animal>
fishes.Add(new Fish("Guppy"));


Here, the compiler could allow this piece of code, even though the method returns List<Animal> simply because all fishes are animals, so if we just changed the types to this:



List<Animal> fishes = GetAccessToFishes();
fishes.Add(new Fish("Guppy"));


Then it would work, but the compiler cannot determine that you're not trying to do this:



List<Fish> fishes = GetAccessToFishes(); // for some reason, returns List<Animal>
Fish firstFist = fishes[0];


Since the list is actually a list of animals, this is not allowed.



So contra- and co-variance is how you treat object references and what you're allowed to do with them.



The in and out keywords in C# 4.0 specifically marks the interface as one or the other. With in, you're allowed to place the generic type (usually T) in input-positions, which means method arguments, and write-only properties.



With out, you're allowed to place the generic type in output-positions, which is method return values, read-only properties, and out method parameters.



This will allow you to do what intended to do with the code:



IEnumerable<Animal> animals = GetFishes(); // returns IEnumerable<Fish>
// since we can only get animals *out* of the collection, every fish is an animal
// so this is safe


List<T> has both in- and out-directions on T, so it is neither co-variant nor contra-variant, but an interface that allowed you to add objects, like this:



interface IWriteOnlyList<in T>
{
void Add(T value);
}


would allow you to do this:



IWriteOnlyList<Fish> fishes = GetWriteAccessToAnimals(); // still returns
IWriteOnlyList<Animal>
fishes.Add(new Fish("Guppy")); <-- this is now safe




Here's a few videos that shows the concepts:




  • Covariance and Contravariance - VS2010 C# Part 1 of 3

  • Covariance and Contravariance - VS2010 C# Part 2 of 3

  • Covariance and Contravariance - VS2010 C# Part 3 of 3


Here's an example:



namespace SO2719954
{
class Base { }
class Descendant : Base { }

interface IBibbleOut<out T> { }
interface IBibbleIn<in T> { }

class Program
{
static void Main(string args)
{
// We can do this since every Descendant is also a Base
// and there is no chance we can put Base objects into
// the returned object, since T is "out"
// We can not, however, put Base objects into b, since all
// Base objects might not be Descendant.
IBibbleOut<Base> b = GetOutDescendant();

// We can do this since every Descendant is also a Base
// and we can now put Descendant objects into Base
// We can not, however, retrieve Descendant objects out
// of d, since all Base objects might not be Descendant
IBibbleIn<Descendant> d = GetInBase();
}

static IBibbleOut<Descendant> GetOutDescendant()
{
return null;
}

static IBibbleIn<Base> GetInBase()
{
return null;
}
}
}


Without these marks, the following could compile:



public List<Descendant> GetDescendants() ...
List<Base> bases = GetDescendants();
bases.Add(new Base()); <-- uh-oh, we try to add a Base to a Descendant


or this:



public List<Base> GetBases() ...
List<Descendant> descendants = GetBases(); <-- uh-oh, we try to treat all Bases
as Descendants






share|improve this answer














share|improve this answer



share|improve this answer








edited Dec 9 '17 at 16:59









gcbs_fln

387




387










answered Apr 27 '10 at 9:29









Lasse Vågsæther Karlsen

285k82517715




285k82517715












  • Hmm, would you be able to explain the goal of covariance and contravariance? It might help me to understand it more.
    – NibblyPig
    Apr 27 '10 at 9:34






  • 1




    See the last bit, which is what the compiler prevented before, the purpose of in and out is to say what you can do with the interfaces (or types) that is safe, so that the compiler won't prevent you from doing safe things.
    – Lasse Vågsæther Karlsen
    Apr 27 '10 at 9:54










  • Superb answer, I watched the videos they were very helpful, and combined with your example I have it sorted now. Only one question remains, and that is why are 'out' and 'in' required, why doesn't visual studio automatically know what you are trying to do (or whats the reason behind it)?
    – NibblyPig
    Apr 27 '10 at 10:19










  • Automagic "I see what you're trying to do there" is usually frowned upon when it comes to declaring stuff like classes, it is better to have the programmer explicitly mark the types. You can try adding "in" to a class that has methods that return T and the compiler will complain. Imagine what would happen if it silently just removed the "in" it had previously automatically added for you.
    – Lasse Vågsæther Karlsen
    Apr 27 '10 at 10:27






  • 1




    If one keyword needs this long explanation, something is clearly wrong. In my opinion, C# is trying to be too smart in this particular case. Nonetheless, thank you for cool explanation.
    – rr-
    Jun 5 '14 at 6:58


















  • Hmm, would you be able to explain the goal of covariance and contravariance? It might help me to understand it more.
    – NibblyPig
    Apr 27 '10 at 9:34






  • 1




    See the last bit, which is what the compiler prevented before, the purpose of in and out is to say what you can do with the interfaces (or types) that is safe, so that the compiler won't prevent you from doing safe things.
    – Lasse Vågsæther Karlsen
    Apr 27 '10 at 9:54










  • Superb answer, I watched the videos they were very helpful, and combined with your example I have it sorted now. Only one question remains, and that is why are 'out' and 'in' required, why doesn't visual studio automatically know what you are trying to do (or whats the reason behind it)?
    – NibblyPig
    Apr 27 '10 at 10:19










  • Automagic "I see what you're trying to do there" is usually frowned upon when it comes to declaring stuff like classes, it is better to have the programmer explicitly mark the types. You can try adding "in" to a class that has methods that return T and the compiler will complain. Imagine what would happen if it silently just removed the "in" it had previously automatically added for you.
    – Lasse Vågsæther Karlsen
    Apr 27 '10 at 10:27






  • 1




    If one keyword needs this long explanation, something is clearly wrong. In my opinion, C# is trying to be too smart in this particular case. Nonetheless, thank you for cool explanation.
    – rr-
    Jun 5 '14 at 6:58
















Hmm, would you be able to explain the goal of covariance and contravariance? It might help me to understand it more.
– NibblyPig
Apr 27 '10 at 9:34




Hmm, would you be able to explain the goal of covariance and contravariance? It might help me to understand it more.
– NibblyPig
Apr 27 '10 at 9:34




1




1




See the last bit, which is what the compiler prevented before, the purpose of in and out is to say what you can do with the interfaces (or types) that is safe, so that the compiler won't prevent you from doing safe things.
– Lasse Vågsæther Karlsen
Apr 27 '10 at 9:54




See the last bit, which is what the compiler prevented before, the purpose of in and out is to say what you can do with the interfaces (or types) that is safe, so that the compiler won't prevent you from doing safe things.
– Lasse Vågsæther Karlsen
Apr 27 '10 at 9:54












Superb answer, I watched the videos they were very helpful, and combined with your example I have it sorted now. Only one question remains, and that is why are 'out' and 'in' required, why doesn't visual studio automatically know what you are trying to do (or whats the reason behind it)?
– NibblyPig
Apr 27 '10 at 10:19




Superb answer, I watched the videos they were very helpful, and combined with your example I have it sorted now. Only one question remains, and that is why are 'out' and 'in' required, why doesn't visual studio automatically know what you are trying to do (or whats the reason behind it)?
– NibblyPig
Apr 27 '10 at 10:19












Automagic "I see what you're trying to do there" is usually frowned upon when it comes to declaring stuff like classes, it is better to have the programmer explicitly mark the types. You can try adding "in" to a class that has methods that return T and the compiler will complain. Imagine what would happen if it silently just removed the "in" it had previously automatically added for you.
– Lasse Vågsæther Karlsen
Apr 27 '10 at 10:27




Automagic "I see what you're trying to do there" is usually frowned upon when it comes to declaring stuff like classes, it is better to have the programmer explicitly mark the types. You can try adding "in" to a class that has methods that return T and the compiler will complain. Imagine what would happen if it silently just removed the "in" it had previously automatically added for you.
– Lasse Vågsæther Karlsen
Apr 27 '10 at 10:27




1




1




If one keyword needs this long explanation, something is clearly wrong. In my opinion, C# is trying to be too smart in this particular case. Nonetheless, thank you for cool explanation.
– rr-
Jun 5 '14 at 6:58




If one keyword needs this long explanation, something is clearly wrong. In my opinion, C# is trying to be too smart in this particular case. Nonetheless, thank you for cool explanation.
– rr-
Jun 5 '14 at 6:58












up vote
5
down vote













This post is the best I've read on the subject



In short, covariance / contravariance /invariance deals with automatic type casting (from base to derived and vice-versa). Those type casts are possible only if some guarantees are respected in terms of read / write actions performed on the casted objects.
Read the post for more details.






share|improve this answer























  • very good article indeed. :) thanks
    – gsimoes
    May 24 '16 at 0:48






  • 5




    Link appears dead. Here's an archived version: web.archive.org/web/20140626123445/http://adamnathan.co.uk/…
    – si618
    Aug 23 '16 at 7:32

















up vote
5
down vote













This post is the best I've read on the subject



In short, covariance / contravariance /invariance deals with automatic type casting (from base to derived and vice-versa). Those type casts are possible only if some guarantees are respected in terms of read / write actions performed on the casted objects.
Read the post for more details.






share|improve this answer























  • very good article indeed. :) thanks
    – gsimoes
    May 24 '16 at 0:48






  • 5




    Link appears dead. Here's an archived version: web.archive.org/web/20140626123445/http://adamnathan.co.uk/…
    – si618
    Aug 23 '16 at 7:32















up vote
5
down vote










up vote
5
down vote









This post is the best I've read on the subject



In short, covariance / contravariance /invariance deals with automatic type casting (from base to derived and vice-versa). Those type casts are possible only if some guarantees are respected in terms of read / write actions performed on the casted objects.
Read the post for more details.






share|improve this answer














This post is the best I've read on the subject



In short, covariance / contravariance /invariance deals with automatic type casting (from base to derived and vice-versa). Those type casts are possible only if some guarantees are respected in terms of read / write actions performed on the casted objects.
Read the post for more details.







share|improve this answer














share|improve this answer



share|improve this answer








edited Jul 5 '17 at 10:07









Hakam Fostok

5,12183863




5,12183863










answered Jan 4 '15 at 16:09









Ben G

3,54222529




3,54222529












  • very good article indeed. :) thanks
    – gsimoes
    May 24 '16 at 0:48






  • 5




    Link appears dead. Here's an archived version: web.archive.org/web/20140626123445/http://adamnathan.co.uk/…
    – si618
    Aug 23 '16 at 7:32




















  • very good article indeed. :) thanks
    – gsimoes
    May 24 '16 at 0:48






  • 5




    Link appears dead. Here's an archived version: web.archive.org/web/20140626123445/http://adamnathan.co.uk/…
    – si618
    Aug 23 '16 at 7:32


















very good article indeed. :) thanks
– gsimoes
May 24 '16 at 0:48




very good article indeed. :) thanks
– gsimoes
May 24 '16 at 0:48




5




5




Link appears dead. Here's an archived version: web.archive.org/web/20140626123445/http://adamnathan.co.uk/…
– si618
Aug 23 '16 at 7:32






Link appears dead. Here's an archived version: web.archive.org/web/20140626123445/http://adamnathan.co.uk/…
– si618
Aug 23 '16 at 7:32




















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.





Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


Please pay close attention to the following guidance:


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f2719954%2funderstanding-covariant-and-contravariant-interfaces-in-c-sharp%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Berounka

Sphinx de Gizeh

Different font size/position of beamer's navigation symbols template's content depending on regular/plain...