How to "carry" covariance through multiple interfaces - c#

I've got an interface structure that looks like this:
At the most basic level is an IDataProducer with this definition:
public interface IDataProducer<out T>
{
IEnumerable<T> GetRecords();
}
and an IDataConsumer that looks like this:
public interface IDataConsumer<out T>
{
IDataProducer<T> Producer { set; }
}
Finally, I've got an IWriter that derives off of IDataConsumer like so:
public interface IWriter<out T> : IDataConsumer<T>
{
String FileToWriteTo { set; }
void Start();
}
I wanted to make IWriter's generic type T covariant so that I could implement a Factory method to create Writers that could handle different objects without having to know what type would be returned ahead of time. This was implemented by marking the generic type "out". The problem is, I'm having a compile error on IDataConsumer because of this:
Invalid variance: The type parameter 'T' must be contravariantly valid on 'IDataConsumer<T>.Producer'. 'T' is covariant.
I'm not really sure how this can be. It looks to me like the generic type is marked as covariant through the whole chain of interfaces, but it is very possible I don't totally understand how covariance works. Can someone explain to me what I am doing wrong?

The problem is that your Producer property is write-only. That is, you are actually using T in a contravariant way, by passing the value that is generic on type T into the implementer of the interface, rather than the implementer passing it out.
One of the things I like best about the way the C# language design team handled the variance feature in generic interfaces is that the keywords used to denote covariant and contravariant type parameters are mnemonic with the way the parameters are used. I always have a hard time remembering what the words "covariant" and "contravariant" mean, but I never have any trouble remembering what out T vs. in T means. The former means that you promise to only return T values from the interface (e.g. method return values or property getters), while the latter means that you promise to only accept T values into the interface (e.g. method parameters or property setters).
You broke that promise by providing a setter for the Producer property.
Depending on how these interfaces are implemented, it's possible what you want is interface IDataConsumer<in T> instead. That would at least compile. :) And as long as the IDataConsumer<T> implementation really is only consuming the T values, that would probably work. Hard to say without a more complete example.

Peter's answer is correct. To add to it: it helps to try out some examples and see what goes wrong. Suppose the code you had originally was allowed by the compiler. We could then say:
class TigerConsumer : IDataConsumer<Tiger>
{
public IDataProducer<Tiger> p;
public IDataProducer<Tiger> Producer { set { p = value; } }
... and so on ...
}
class GiraffeProducer : IDataProducer<Giraffe>
{
public IEnumerable<Giraffe> GetRecords() {
yield return new Giraffe();
}
TigerConsumer t = new TigerConsumer();
IDataConsumer<Mammal> m = t; // compatible with IDataConsumer<Mammal>
m.Producer = new GiraffeProducer(); // compatible with IDataProducer<Mammal>
foreach(Tiger tiger in t.p.GetRecords())
// And we just cast a giraffe to tiger
Every step on the way here is perfectly typesafe but the program is plainly wrong. Either one of those conversions has to be illegal, or one of the interfaces is not safe for covariance. We wish all those conversions to be legal, and therefore we must detect the lack of type safety in your interface declarations.

Related

Using a generic with an unspecified type parameter as a value in a Dictionary

I'm writing a method that returns a different instance of a class based on the type passed in, for a load process.
The method I'm trying to write will be used like:
Loader<MyType> loader = context.GetLoader<MyType>();
loader.Load(myTypeArray);
Internally, I'm planning on keeping a Dictionary<Type, T> with the loader as the value. However, I'm not sure what type T should be.
I could make T object, but I'd prefer to keep it as some sort of Loader<>. I know I'll need to cast it either way, but using Loader<> would give a little more type safety.
Is there any good way to implement this?
You have two choices. Both require you to add an interface.
Add a plain ILoader (with no type arguments) interface, and implement it in your loader as class Loader<T> : ILoader. The common interface will allow you to store all loaders in a List<ILoader>.
interface ILoader {}
class Loader<T> : ILoader {}
void Example()
{
var loaders = new List<ILoader>();
loaders.Add( new Loader<Foo>() );
loaders.Add( new Loader<Bar>() );
}
Define a new covariant interface ILoader<out T> and implement it in your Loader as class Loader<T> : ILoader<T>. The covariance will allow you to store all loaders in a List<ILoader<object>>. This option only works if T is a reference type, and is only viable if none of your interface methods accept T as an argument.
interface ILoader<out T>
{
//void SetLoader(T input); //Does not compile due to covariance
T GetLoader(); //Read is allowed
}
class Loader<T> : ILoader<T>
{
public void SetLoader(T input) {} //Works when not in interface
public T GetLoader() { return default(T); }
}
void Example()
{
var loaders = new List<ILoader<object>>();
loaders.Add( new Loader<Foo>() );
loaders.Add( new Loader<Bar>() );
}
Code sample on DotNetFiddle
I could make T object, but I'd prefer to keep it as some sort of Loader<>. I know I'll need to cast it either way, but using Loader<> would give a little more type safety.
No it will not; this sentence contradicts itself! You say both "I know I'll need to cast" so there is already zero compile-time type safety, and that you can get more type safety, but zero is not more than zero!
Remember the function of a representation-preserving cast is precisely "I know a fact that will be true at runtime that the compiler does not know at compile time". That's the purpose of a cast.
There is no way to represent in the C# type system "this is a thing of type C<?>", so don't try to find one. You've already embraced run-time type checking, so go for it. You have an invariant that your dict[typeof(T)] produces something of type Loader<T>; the only person that can maintain that invariant is you, so don't even try to rely on the compiler to do it for you.

cast of generic type fails

I am unable to cast a generic type to another generic type, besides the cast should be valid
What I want to archive is in short (for MyModel implementing IModel, and MyImplementation implementing IImplementation):
IImplementation<IModel> implementation = new MyImplementation<MyModel>();
Assert.IsNull(implementation as IImplementation<IModel>);
This is a bit confusing, as the type should be valid.
Complete conceptual model:
interface IModel {}
class MyModel : IModel {}
interface IImplementation<TModel> where TModel : IModel { }
class MyImplementation<TModel> : IImplementation<TModel>
where TModel : IModel { }
public void CallRegister()
{
var implementation = new MyImplementation<MyModel>();
var instance = CastModel(implementation);
Assert.IsNotNull(instance); //this assert fails!
}
private object CastModel<TModel>(IImplementation<TModel> implementation) where TModel : IModel
{
return implementation as IImplementation<IModel>;
}
I need this cast to enable me to save multiple IImplementations to the same Dictionary<Type, IImplementation<IModel>>, where the key is obtained by doing typeof(TModel).
To do this type safe I don't want to use a Dictionary<Type, object>.
Why does the cast fail? Are there additional resources to this? Its a similar question to Invalid Cast of Type Constrained C# Generic, but it is not explained why there just that it does not work.
What is the best way to archive a functionality similar to the dictionary as explained above if this kind of cast is not possible?
Though Olivier's answer gets the idea across about why this usually goes wrong, there is a way to make this work in your program.
The feature you want is called generic interface covariance. Covariance is the property that if a Cat is an Animal, then an IFoo<Cat> is an IFoo<Animal>.
Covariance in C# only works in the following situations:
The "outer" type is an interface, delegate or array. No classes or structs.
If an interface or delegate, the type must be marked at compile time as supporting covariance. Arrays get (unsafe!) covariance for free.
The "inner" types -- the types that are varying -- are both reference types. You can't say that an IFoo<int> is an IFoo<object> even though an int is an object, because they are not both reference types.
To mark an interface as covariant, you put out before the declaration of the type parameter which you wish to allow to vary:
interface IImplementation<out TModel> where TModel : IModel { }
If you do that, your program will start to work.
HOWEVER, out is a reminder to you that covariance is only safe if T is used in output positions. This is legal:
interface I<out T> {
T M();
}
This is not:
interface I<out T> {
void M(T t);
}
In the first, T is only passed out of things. In the second, it is passed in.
In the first scenario, we cannot use covariance to introduce a type hole. We have an I<Cat> and we cast it to I<Animal>, and now M returns an Animal, but that's OK, because we already know that it will return a Cat, and a Cat is an Animal.
But in the second scenario, we have the opposite situation. If we allowed an I<Cat> to be converted to I<Animal> then we have an M that can take a Turtle, but the real implementation can only handle Cats. That's why C# will make this illegal.
So go forth and use covariance, but remember that you have to certify to the compiler that you want it, and that it is safe under all circumstances. If you don't want it, or it is not safe, then you don't get to have covariance, and you'll have to find a different solution to your problem.
This kind of conversion is not allowed for good reasons. Let's take an example where the problem is more obvious. We have the classes Animal, Cat : Animal and Dog : Animal. Now let's do this:
List<Animal> list = new List<Cat>(); // Seems to be possible at first glance.
// An now comes the problem:
list.Add(new Dog()); // Seems to be possible as well.
But wait! The list is in reality a list of cats! And we are trying to add a dog. Even adding new Animal() to list, which is statically typed as List<Animal>, would not work.
Therefore two types T<A> and T<B> are not assignment compatible in C#, even if A and B are!
You need another approach.
What you can do is to wrap your dictionary in a class with a generic method having a generic type constraint.
public class MyImplementationDict
{
private readonly Dictionary<Type, object> _internalDict = new Dictionary<Type, object>();
public void Add<T>(IImplementation<T> item)
where T : IModel
{
_internalDict.Add(typeof(T), item);
}
...
}

How the CLR implements IEnumerable<T> on Arrays? [duplicate]

So as you may know, arrays in C# implement IList<T>, among other interfaces. Somehow though, they do this without publicly implementing the Count property of IList<T>! Arrays have only a Length property.
Is this a blatant example of C#/.NET breaking its own rules about the interface implementation or am I missing something?
So as you may know, arrays in C# implement IList<T>, among other interfaces
Well, yes, erm no, not really. This is the declaration for the Array class in the .NET 4 framework:
[Serializable, ComVisible(true)]
public abstract class Array : ICloneable, IList, ICollection, IEnumerable,
IStructuralComparable, IStructuralEquatable
{
// etc..
}
It implements System.Collections.IList, not System.Collections.Generic.IList<>. It can't, Array is not generic. Same goes for the generic IEnumerable<> and ICollection<> interfaces.
But the CLR creates concrete array types on the fly, so it could technically create one that implements these interfaces. This is however not the case. Try this code for example:
using System;
using System.Collections.Generic;
class Program {
static void Main(string[] args) {
var goodmap = typeof(Derived).GetInterfaceMap(typeof(IEnumerable<int>));
var badmap = typeof(int[]).GetInterfaceMap(typeof(IEnumerable<int>)); // Kaboom
}
}
abstract class Base { }
class Derived : Base, IEnumerable<int> {
public IEnumerator<int> GetEnumerator() { return null; }
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); }
}
The GetInterfaceMap() call fails for a concrete array type with "Interface not found". Yet a cast to IEnumerable<> works without a problem.
This is quacks-like-a-duck typing. It is the same kind of typing that creates the illusion that every value type derives from ValueType which derives from Object. Both the compiler and the CLR have special knowledge of array types, just as they do of value types. The compiler sees your attempt at casting to IList<> and says "okay, I know how to do that!". And emits the castclass IL instruction. The CLR has no trouble with it, it knows how to provide an implementation of IList<> that works on the underlying array object. It has built-in knowledge of the otherwise hidden System.SZArrayHelper class, a wrapper that actually implements these interfaces.
Which it doesn't do explicitly like everybody claims, the Count property you asked about looks like this:
internal int get_Count<T>() {
//! Warning: "this" is an array, not an SZArrayHelper. See comments above
//! or you may introduce a security hole!
T[] _this = JitHelpers.UnsafeCast<T[]>(this);
return _this.Length;
}
Yes, you can certainly call that comment "breaking the rules" :) It is otherwise darned handy. And extremely well hidden, you can check this out in SSCLI20, the shared source distribution for the CLR. Search for "IList" to see where the type substitution takes place. The best place to see it in action is clr/src/vm/array.cpp, GetActualImplementationForArrayGenericIListMethod() method.
This kind of substitution in the CLR is pretty mild compared to what happens in the language projection in the CLR that allows writing managed code for WinRT (aka Metro). Just about any core .NET type gets substituted there. IList<> maps to IVector<> for example, an entirely unmanaged type. Itself a substitution, COM doesn't support generic types.
Well, that was a look at what happens behind the curtain. It can be very uncomfortable, strange and unfamiliar seas with dragons living at the end of the map. It can be very useful to make the Earth flat and model a different image of what's really going on in managed code. Mapping it to everybody favorite answer is comfortable that way. Which doesn't work so well for value types (don't mutate a struct!) but this one is very well hidden. The GetInterfaceMap() method failure is the only leak in the abstraction that I can think of.
New answer in the light of Hans's answer
Thanks to the answer given by Hans, we can see the implementation is somewhat more complicated than we might think. Both the compiler and the CLR try very hard to give the impression that an array type implements IList<T> - but array variance makes this trickier. Contrary to the answer from Hans, the array types (single-dimensional, zero-based anyway) do implement the generic collections directly, because the type of any specific array isn't System.Array - that's just the base type of the array. If you ask an array type what interfaces it supports, it includes the generic types:
foreach (var type in typeof(int[]).GetInterfaces())
{
Console.WriteLine(type);
}
Output:
System.ICloneable
System.Collections.IList
System.Collections.ICollection
System.Collections.IEnumerable
System.Collections.IStructuralComparable
System.Collections.IStructuralEquatable
System.Collections.Generic.IList`1[System.Int32]
System.Collections.Generic.ICollection`1[System.Int32]
System.Collections.Generic.IEnumerable`1[System.Int32]
For single-dimensional, zero-based arrays, as far as the language is concerned, the array really does implement IList<T> too. Section 12.1.2 of the C# specification says so. So whatever the underlying implementation does, the language has to behave as if the type of T[] implements IList<T> as with any other interface. From this perspective, the interface is implemented with some of the members being explicitly implemented (such as Count). That's the best explanation at the language level for what's going on.
Note that this only holds for single-dimensional arrays (and zero-based arrays, not that C# as a language says anything about non-zero-based arrays). T[,] doesn't implement IList<T>.
From a CLR perspective, something funkier is going on. You can't get the interface mapping for the generic interface types. For example:
typeof(int[]).GetInterfaceMap(typeof(ICollection<int>))
Gives an exception of:
Unhandled Exception: System.ArgumentException: Interface maps for generic
interfaces on arrays cannot be retrived.
So why the weirdness? Well, I believe it's really due to array covariance, which is a wart in the type system, IMO. Even though IList<T> is not covariant (and can't be safely), array covariance allows this to work:
string[] strings = { "a", "b", "c" };
IList<object> objects = strings;
... which makes it look like typeof(string[]) implements IList<object>, when it doesn't really.
The CLI spec (ECMA-335) partition 1, section 8.7.1, has this:
A signature type T is compatible-with a signature type U if and only if at least one of the following holds
...
T is a zero-based rank-1 array V[], and U is IList<W>, and V is array-element-compatible-with W.
(It doesn't actually mention ICollection<W> or IEnumerable<W> which I believe is a bug in the spec.)
For non-variance, the CLI spec goes along with the language spec directly. From section 8.9.1 of partition 1:
Additionally, a created vector with element type T, implements the interface System.Collections.Generic.IList<U>, where U := T. (§8.7)
(A vector is a single-dimensional array with a zero base.)
Now in terms of the implementation details, clearly the CLR is doing some funky mapping to keep the assignment compatibility here: when a string[] is asked for the implementation of ICollection<object>.Count, it can't handle that in quite the normal way. Does this count as explicit interface implementation? I think it's reasonable to treat it that way, as unless you ask for the interface mapping directly, it always behaves that way from a language perspective.
What about ICollection.Count?
So far I've talked about the generic interfaces, but then there's the non-generic ICollection with its Count property. This time we can get the interface mapping, and in fact the interface is implemented directly by System.Array. The documentation for the ICollection.Count property implementation in Array states that it's implemented with explicit interface implementation.
If anyone can think of a way in which this kind of explicit interface implementation is different from "normal" explicit interface implementation, I'd be happy to look into it further.
Old answer around explicit interface implementation
Despite the above, which is more complicated because of the knowledge of arrays, you can still do something with the same visible effects through explicit interface implementation.
Here's a simple standalone example:
public interface IFoo
{
void M1();
void M2();
}
public class Foo : IFoo
{
// Explicit interface implementation
void IFoo.M1() {}
// Implicit interface implementation
public void M2() {}
}
class Test
{
static void Main()
{
Foo foo = new Foo();
foo.M1(); // Compile-time failure
foo.M2(); // Fine
IFoo ifoo = foo;
ifoo.M1(); // Fine
ifoo.M2(); // Fine
}
}
IList<T>.Count is implemented explicitly:
int[] intArray = new int[10];
IList<int> intArrayAsList = (IList<int>)intArray;
Debug.Assert(intArrayAsList.Count == 10);
This is done so that when you have a simple array variable, you don't have both Count and Length directly available.
In general, explicit interface implementation is used when you want to ensure that a type can be used in a particular way, without forcing all consumers of the type to think about it that way.
Edit: Whoops, bad recall there. ICollection.Count is implemented explicitly. The generic IList<T> is handled as Hans descibes below.
Explicit interface implementation. In short, you declare it like void IControl.Paint() { } or int IList<T>.Count { get { return 0; } }.
It's no different than an explicit interface implementation of IList. Just because you implement the interface doesn't mean its members need to appear as class members. It does implement the Count property, it just doesn't expose it on X[].
With reference-sources being available:
//----------------------------------------------------------------------------------------
// ! READ THIS BEFORE YOU WORK ON THIS CLASS.
//
// The methods on this class must be written VERY carefully to avoid introducing security holes.
// That's because they are invoked with special "this"! The "this" object
// for all of these methods are not SZArrayHelper objects. Rather, they are of type U[]
// where U[] is castable to T[]. No actual SZArrayHelper object is ever instantiated. Thus, you will
// see a lot of expressions that cast "this" "T[]".
//
// This class is needed to allow an SZ array of type T[] to expose IList<T>,
// IList<T.BaseType>, etc., etc. all the way up to IList<Object>. When the following call is
// made:
//
// ((IList<T>) (new U[n])).SomeIListMethod()
//
// the interface stub dispatcher treats this as a special case, loads up SZArrayHelper,
// finds the corresponding generic method (matched simply by method name), instantiates
// it for type <T> and executes it.
//
// The "T" will reflect the interface used to invoke the method. The actual runtime "this" will be
// array that is castable to "T[]" (i.e. for primitivs and valuetypes, it will be exactly
// "T[]" - for orefs, it may be a "U[]" where U derives from T.)
//----------------------------------------------------------------------------------------
sealed class SZArrayHelper {
// It is never legal to instantiate this class.
private SZArrayHelper() {
Contract.Assert(false, "Hey! How'd I get here?");
}
/* ... snip ... */
}
Specifically this part:
the interface stub dispatcher treats this as a special case, loads up
SZArrayHelper, finds the corresponding generic method (matched simply
by method name), instantiates it for type and executes it.
(Emphasis mine)
Source (scroll up).

Parameter constraints - call method to check type in constraint?

I have a method with a generic parameter:
internal void DoSomething<T>(T workWithThis)
{
}
I now want to constrain this method to only accept parameters which inherit one of a few interfaces I'd like to specify. However I have not yet found a way to it. What I'd like looks like this:
internal void DoSomething<T>(T workWithThis) where T : ISomething | ISomethingElse
{
}
Obviously this is not working, so I tried it with a static method to check the Type of T:
public static bool CheckType(Type t)
{
return */check here*/
}
internal void DoSomething<T>(T workWithThis) where T : CheckType(typeof(T))
{
}
Obviously this is not going to work either. The question is why? Why is the compiler preventing me from doing that, based on my understanding there is no reason for it not to work
Why is the compiler preventing me from doing that, based on my understanding there is no reason for it not to work
The compiler is preventing you from doing it because you're trying to do something which isn't supported by C# as a language. The syntax you're trying to use does not comply with the productions in section 10.1.5 of the C# spec.
C# as a language simply does not support the scenario you require.
Now as for why the language doesn't allow this sort of flexibility - that comes down to the normal balancing act of:
How many developers would benefit from this and how much
Extra burden on other developers to understand a more complicated language
Resources (primarily within Microsoft) required to design the language feature, implement and test it
Oh, and of course this isn't just C# - the CLR would have to support such a restriction as well, and it would at least encourage other CLR languages to understand it too.
I suggest you solve this by having two separate methods. Note that they can't just be overloads of generic methods, as overloads cannot differ only by generic type constraints. If you don't mind about boxing for value types implementing the interface, you could overload with:
internal void DoSomething(ISomething something)
{
}
internal void DoSomething(ISomethingElse somethingElse)
{
}
... although then if you pass in a value where the expression is a type implementing both interfaces, you'll end up with overload ambiguity.
Alternatively, just give the two methods different names.
The compiler has to verify all the constraints at compile time, and cannot call a method to do so.
The only things you can specify in the where constraints are:
new() - require a parameterless constructor
class - must be a reference type
struct - must be a value type
SomeBaseClass
ISomeInterface
T : U - must be, inherit from, or implement one of the other generic parameters
See the C# Programming Guide - Constraints on Type Parameters for more information.
As for why, you should never have to answer "I see no reason for this to work". You have to start in the opposite direction, "Why should this work", and then come up with enough plausible and realistic scenarios and requirements to make it worthwhile to implement. See Minus 100 Points by Eric Gunnerson.
To fix this in your code, you should derive both interfaces from a common interface, and add a constraint on that instead.
If the two interfaces have nothing in common, then I question the benefit of actually adding a constraint in the first place.
For instance, if your code is going to call a method on the objects being used with the generic type/method, then obviously both interfaces have to have the same notion about what that method is, and the only way to do that would be for the method to be defined in a common base interface. That the two interfaces happen to have the same method or property declared, with the same signature, does not make it the same method.
Having said that, are you sure you even need generics here?
How about just declaring two methods, each taking one such interface?
internal void DoSomething(ISomething workWithThis)
internal void DoSomething(ISomethingElse workWithThis)
The compiler uses the generic constraint to determine what operations is available on T within the generic method - so allowing an or expression would not be type safe. For example you have two interfaces IFirst and ISecond:
public interface IFirst
{
void First();
}
public interface ISecond
{
void Second();
}
internal void DoSomething<T>(T workWithThis) where T : IFirst or ISecond
{
//How to call this method if the type is ISecond
workWithThis.First();
//How to call this method if the type is IFirst
workWithThis.Second();
}
You can define an empty interface that holds all of them.
Remember, that in C# interfaces can have multiple inheritance.
For example:
public interface IHolder : ISomething, ISomethingElse
{
}
and for generic
internal void DoSomething<T>(T workWithThis) where T : IHolder
{
}

Covariant generic parameter

I'm trying to understand this but I didn't get any appropriate results from searching.
In C# 4, I can do
public interface IFoo<out T>
{
}
How is this different from
public interface IFoo<T>
{
}
All I know is the out makes the generic parameter covariant (??).
Can someone explain the usage of <out T> part with an example? And also why is applicable only for interfaces and delegates and not for classes?
Sorry if it's a duplicate and close it as such if it is.
Can someone explain the usage of the out T part with an example?
Sure. IEnumerable<T> is covariant. That means you can do this:
static void FeedAll(IEnumerable<Animal> animals)
{
foreach(Animal animal in animals) animal.Feed();
}
...
IEnumerable<Giraffe> giraffes = GetABunchOfGiraffes();
FeedAll(giraffes);
"Covariant" means that the assignment compatibility relationship of the type argument is preserved in the generic type. Giraffe is assignment compatible with Animal, and therefore that relationship is preserved in the constructed types: IEnumerable<Giraffe> is assignment compatible with IEnumerable<Animal>.
Why is applicable only for interfaces and delegates and not for classes?
The problem with classes is that classes tend to have mutable fields. Let's take an example. Suppose we allowed this:
class C<out T>
{
private T t;
OK, now think this question through carefully before you go on. Can C<T> have any method outside of the constructor that sets the field t to something other than its default?
Because it must be typesafe, C<T> can now have no methods that take a T as an argument; T can only be returned. So who sets t, and where do they get the value they set it from?
Covariant class types really only work if the class is immutable. And we don't have a good way to make immutable classes in C#.
I wish we did, but we have to live with the CLR type system that we were given. I hope in the future we can have better support for both immutable classes, and for covariant classes.
If this feature interests you, consider reading my long series on how we designed and implemented the feature. Start from the bottom:
https://blogs.msdn.microsoft.com/ericlippert/tag/covariance-and-contravariance/
If we're talking about generic variance:
Covariance is all about values being returned from an operation back to the caller.
Contravariance It’s opposite and it's about values being passed into by the caller:
From what I know if a type parameter is only used for output, you can use out. However if the type is only used for input, you can use in. It's the convenience because the compiler cannot be sure if you can remember which form is called covariance and which is called contravariance. If you don't declare them explicitly once the type has been declared, the relevant types of conversion are available implicitly.
There is no variance (either covariance or contravariance) in classes because even if you have a class that only uses the type parameter for input (or only uses it for output), you
can’t specify the in or out modifiers. Only interfaces and delegates can have variant type parameters. Firstly the CLR doesn’t allow it. From the conceptual point of view Interfaces represent a way of looking at an object from a particular perspective, whereas classes are more actual implementation types.
It means that if you have this:
class Parent { }
class Child : Parent { }
Then an instance of IFoo<Child> is also an instance of IFoo<Parent>.

Categories

Resources