4
 public interface IOInitializable<in ItemType>

What does contravariant: converting from narrower (circle) to wider (Shapes)

mean for an interface?

What are the consequence and the dangers?

I've read http://msdn.microsoft.com/en-us/library/dd469484.aspx but this does not help me.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
  • 1
    I personally believe that MSDN is not good at explaining thing, although is a great for reference. – Asif Mushtaq Nov 16 '12 at 09:29
  • 1
    Stackoverflow itself has got answer..[Post by Lasse V. Karlsen][1] [1]: http://stackoverflow.com/questions/2719954/understanding-covariant-and-contravariant-interfaces-in-c-sharp – hridya pv Nov 16 '12 at 09:33

2 Answers2

3

I'd recommend reading this explaination from Tomas:

The theory behind covariance and contravariance in C# 4

It boils down to the fact that if you have a method call that is passing a number of "Circles", you can use a function that accepts a number of "Shapes" as long as it doesn't return a "Shape" (because that may or may not be a "Circle").

Grhm
  • 6,726
  • 4
  • 40
  • 64
  • i don't undestand what this has to do with return type? – Bernhard Koenig Nov 16 '12 at 12:39
  • Using `IComparer` as the example, the only function it provides is the `Compare(T a,T b)` which returns an `int`. You can use `IComparer` in place of `IComparer` because it only reads the input (Cirlces and Shapes), but does not output them. – Grhm Nov 16 '12 at 12:51
  • As a further example, if `IMyComparer` has a method `T GetLatest(T a, T b)` which returns `T`, you cannot use a `IMyComparer` when an `ImyComparer` is requested because `IMyComparer` may return a non-circle shape. – Grhm Nov 16 '12 at 12:55
  • @Grhm AWESOME link, thx a million! co(ntra) variance explained in a language my tiny brain is able to understand :) – bas Mar 17 '13 at 08:52
  • I've read your answer a few times but I'm still none the wiser. A code example would be a good addition. The other answer here by @LeviBotelho does a good job at explaining it. – user247702 Feb 14 '17 at 09:06
3

IComparer is a good example to demonstrate this. IComparer looks like this:

IComparer<in T>

Take the following:

IComparer<Primate>
IComparer<Chimpanzee>

where Chimpanzee : Primate (of course). A method which requires an IComparer<Chimpanzee> can take an IComparer<Primate> as an argument, because if the comparer can compare primates, it can also compare chimpanzees, as it uses traits common to the two types to affect the comparison.

A good way to think of this is in terms of functionality. Covariance allows more complex objects to be passed which implement a core functionality (like passing a string for an object). Contravariance does something similar... comparing all primates is more complex than just comparing chimpanzees. It allows you to replace a comparer for a specific type with one which compares a more general type. In this sense, the "in" applies more to the functionality of the method than the actual type passed.

Levi Botelho
  • 24,626
  • 5
  • 61
  • 96
  • so that does mean I can compare more complex types and I m not shrinked on only T if I use in T, is that right? – Bernhard Koenig Nov 16 '12 at 12:37
  • 1
    This means that yes, you can compare more complex types. As is in my example, a primate comparer can also compare chimpanzees, because chimpanzees are in fact primates. Chimpanzees share common traits with primates due to the inheritance relationship, and as such ANY class which implements these common traits can be passed to the comparer. – Levi Botelho Nov 16 '12 at 12:41