开发者

Understanding Covariance and Contravariance in C# 4.0

I watched a video about it on Channel 9 but I didn't really understand it much.

Can someone please give me a simple example about these that's easy to understand? After that maybe how it would be used i开发者_开发知识库n practice?


You may want to look at this blog, he does a fantastic job of explaining it, but I think it will take more examples to clear it up for people, as this gets into a very hard-to-understand area, but, the quote below from the article sums it up well.

http://hestia.typepad.com/flatlander/2008/12/c-covariance-and-contravariance-by-example.html

"covariance and contravariance" means that you can now pass inexact generic types when it's safe to do so, just as you can pass inexact argument types when it's safe to do so.


A Tiger IS an Animal so it can do anything an Animal can do. If I have a method that asks for an Animal I can also pass in a Tiger.

Covariance - Passing a more specific type argument

This is the direction you are most familiar with. I can pass an IEnumerable<Tiger> anywhere that expects an IEnumerable<Animal>.


static void ListAnimals(IEnumerable<Animal> animals)
{
}

List<Tiger> tigers = new List<Tiger>();
ListAnimals(tigers);

Contravariance - Passing a more general type argument.

The 'contra' implies that this goes 'against' the normal conversion flow . This one is trickier because it seem's counter-intuitive until you see it in action.

Say I have a function which expects an IComparer<Tiger> and two tigers to be compared. Contravariance says I can also pass in the more general IComparer<Animal> because it can also compare two tigers (since a Tiger IS an animal). It compares them in a more general way, but this is still type safe.


static void CompareTigers(IComparer<Tiger> comparer, Tiger tiger1, Tiger tiger2)
{
    comparer.Compare(tiger1, tiger2);
}

// normal - a tiger comparer can compare two tigers
IComparer<Tiger> tigerComparer = null;
CompareTigers(tigerComparer, new Tiger(), new Tiger());

// contravariance - an animal comparer can ALSO compare two tigers
IComparer<Animal> animalComparer = null;
CompareTigers(animalComparer, new Tiger(), new Tiger());

Note that this also works with delegates. I can pass an Action<Animal> into a function that expects an Action<Tiger> because Tiger objects can also be passed safely to the Action<Animal> delegate.


Eric Lippert came up with a very good explanation in a recent blog post


The following article deals with co- and contravariance with delegates: http://msdn.microsoft.com/en-us/library/ms173174.aspx.

Perhaps it is useful to you, even if you're not into delegates yet. I found it to be quite easy to understand.


MSDN docs for C# 4.0 (and VB) are here: Covariance and Contravariance

If you are interested in concrete examples, they are here:

  • Using Variance in Interfaces for Generic Collections

  • Using Variance in Delegates

  • Using Variance for Func and Action Generic Delegates

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜