.net - Understanding Covariant and Contravariant interfaces in C# -
i've come across these in textbook reading on c#, having difficulty understanding them, due lack of context.
is there concise explanation of , useful out there?
edit clarification:
covariant interface:
interface ibibble<out t> . .
contravariant interface:
interface ibibble<in t> . .
with <out t>
, can treat interface reference 1 upwards in hierarchy.
with <in t>
, can treat interface reference 1 downwards in hiearchy.
let me try explain in more english terms.
let's retrieving list of animals zoo, , intend process them. animals (in zoo) has name, , unique id. animals mammals, reptiles, amphibians, fish, etc. they're animals.
so, list of animals (which contains animals of different types), can animals has name, safe name of animals.
however, if have list of birds only, need treat them animals, work? intuitively, should work, in c# 3.0 , before, piece of code not compile:
ienumerable<animal> animals = getfishes(); // returns ienumerable<fish>
the reason compiler doesn't "know" intend, or can, animals collection after you've retrieved it. knows, there way through ienumerable<t>
put object list, , potentially allow put animal isn't fish, collection supposed contain fish.
in other words, compiler cannot guarantee not allowed:
animals.add(new mammal("zebra"));
so compiler outright refuses compile code. covariance.
let's @ contravariance.
since our zoo can handle animals, can handle fish, let's try add fish our zoo.
in c# 3.0 , before, not compile:
list<fish> fishes = getaccesstofishes(); // reason, returns list<animal> fishes.add(new fish("guppy"));
here, compiler could allow piece of code, though method returns list<animal>
because fish animals, if changed types this:
list<animal> fishes = getaccesstofishes(); fishes.add(new fish("guppy"));
then work, compiler cannot determine you're not trying this:
list<fish> fishes = getaccesstofishes(); // reason, returns list<animal> fish firstfist = fishes[0];
since list list of animals, not allowed.
so contra- , co-variance how treat object references , you're allowed them.
the in
, out
keywords in c# 4.0 marks interface 1 or other. in
, you're allowed place generic type (usually t) in input-positions, means method arguments, , write-only properties.
with out
, you're allowed place generic type in output-positions, method return values, read-only properties, , out method parameters.
this allow intended code:
ienumerable<animal> animals = getfishes(); // returns ienumerable<fish> // since can animals *out* of collection, every fish animal // safe
list<t>
has both in- , out-directions on t, neither co-variant nor contra-variant, interface allowed add objects, this:
interface iwriteonlylist<in t> { void add(t value); }
would allow this:
iwriteonlylist<fish> fishes = getwriteaccesstoanimals(); // still returns iwriteonlylist<animal> fishes.add(new fish("guppy")); <-- safe
here's few videos shows concepts:
- covariance , contravariance - vs2010 c# part 1 of 3
- covariance , contravariance - vs2010 c# part 2 of 3
- covariance , contravariance - vs2010 c# part 3 of 3
here's example:
namespace so2719954 { class base { } class descendant : base { } interface ibibbleout<out t> { } interface ibibblein<in t> { } class program { static void main(string[] args) { // can since every descendant base // , there no chance can put base objects // returned object, since t "out" // can not, however, put base objects b, since // base objects might not descendant. ibibbleout<base> b = getoutdescendant(); // can since every descendant base // , can put descendant objects base // can not, however, retrieve descendant objects out // of d, since base objects might not descendant ibibblein<descendant> d = getinbase(); } static ibibbleout<descendant> getoutdescendant() { return null; } static ibibblein<base> getinbase() { return null; } } }
without these marks, following compile:
public list<descendant> getdescendants() ... list<base> bases = getdescendants(); bases.add(new base()); <-- uh-oh, try add base descendant
or this:
public list<base> getbases() ... list<descendant> descendants = getbases(); <-- uh-oh, try treat bases descendants
Comments
Post a Comment