Information Technology Reference
In-Depth Information
generic interfaces such that they can be treated covariantly, or contravari-
antly. Let's discuss generic covariance first, and then we'll move on to
contravariance.
This method can be called with a List<Planet>:
public static void
CoVariantGeneric(
IEnumerable
<
CelestialBody
> baseItems)
{
foreach
(
var
thing
in
baseItems)
Console
.WriteLine(
"{0} has a mass of {1} Kg"
,
thing.Name, thing.Mass);
}
That's because IEnumerable<T> has been augmented to limit T to only
output positions in its interface:
public interface
IEnumerable
<
out
T> :
IEnumerable
{
IEnumerator
<T> GetEnumerator();
}
public interface
IEnumerator
<
out
T> :
IDisposable
,
IEnumerator
{
T Current {
get
; }
// MoveNext(), Reset() inherited from IEnumerator
}
I included both the IEnumerable<T> and IEnumerator<T> definition
here, because the IEnumerator<T> has the important restrictions. Notice
that IEnumerator<T> now decorates the type parameter T with the
out
modifier. That forces the compiler to limit T to output positions. Output
positions are limited to function return values, property get accessors, and
certain delegate positions.
Therefore, using IEnumerable<out T>, the compiler knows that you will
look at every T in the sequence, but never modify the contents of the source
sequence. Treating every Planet as a CelestialBody in this case works.
IEnumerable<T> can be covariant only because IEnumerator<T> is also
covariant. If IEnumerable<T> returned an interface that was not declared
as covariant, the compiler would generate an error. Covariant types must