Why does C# (4.0) not allow co- and contravariance

2020-01-24 14:04发布

问题:

What is the real reason for that limitation? Is it just work that had to be done? Is it conceptually hard? Is it impossible?

Sure, one couldn't use the type parameters in fields, because they are allways read-write. But that can't be the answer, can it?

The reason for this question is that I'm writing an article on variance support in C# 4, and I feel that I should explain why it is restricted to delegates and interfaces. Just to inverse the onus of proof.

Update: Eric asked about an example.

What about this (don't know if that makes sense, yet :-))

public class Lookup<out T> where T : Animal {
  public T Find(string name) {
    Animal a = _cache.FindAnimalByName(name);
    return a as T;
  }
}

var findReptiles = new Lookup<Reptile>();
Lookup<Animal> findAnimals = findReptiles;

The reason for having that in one class could be the cache that is held in the class itself. And please don't name your different type pets the same!

BTW, this brings me to optional type parameters in C# 5.0 :-)

Update 2: I'm not claiming the CLR and C# should allow this. Just trying to understand what led to that it doesnt.

回答1:

First off, as Tomas says, it is not supported in the CLR.

Second, how would that work? Suppose you have

class C<out T>
{ ... how are you planning on using T in here? ... }

T can only be used in output positions. As you note, the class cannot have any field of type T because the field could be written to. The class cannot have any methods that take a T, because those are logically writes. Suppose you had this feature -- how would you take advantage of it?

This would be useful for immutable classes if we could, say, make it legal to have a readonly field of type T; that way we'd massively cut down on the likelihood that it be improperly written to. But it's quite difficult to come up with other scenarios that permit variance in a typesafe manner.

If you have such a scenario, I'd love to see it. That would be points towards someday getting this implemented in the CLR.

UPDATE: See

Why isn't there generic variance for classes in C# 4.0?

for more on this question.



回答2:

As far as I know, this feature isn't supported by CLR, so adding this would require significant work on the CLR side as well. I believe that co- and contra-variance for interfaces and delegates was actually supported on CLR before the version 4.0, so this was a relatively straightforward extension to implement.

(Supporting this feature for classes would be definitely useful, though!)



回答3:

If they were permitted, useful 100% type-safe (no internal typecasts) classes or structures could be defined which were covariant with regard to their type T, if their constructor accepted one or more T's or T supplier's. Useful, 100%-type-safe classes or structures could be defined which were contravariant with respect to T if their constructors accepted one or more T consumers. I'm not sure there's much advantage of a class over an interface, beyond the ability to use "new" rather than using a static factory method (most likely from a class whose name is similar to that of the interface), but I can certainly see usage cases for having immutable structures support covariance.