A variação será suportada apenas de forma segura - na verdade, usando as habilidades que o CLR já possui. Portanto, os exemplos que dou no livro de tentar usar um List<Banana>como List<Fruit>(ou seja o que for) ainda não funcionarão - mas alguns outros cenários funcionarão.
Em primeiro lugar, ele só terá suporte para interfaces e delegados.
Em segundo lugar, requer que o autor da interface / delegado decore os parâmetros de tipo como in(para contravariância) ou out(para covariância). O exemplo mais óbvio é IEnumerable<T>aquele que só permite que você retire valores "fora" dele - não permite que você adicione novos. Isso vai se tornar IEnumerable<out T>. Isso não prejudica a segurança de tipo, mas permite que você retorne um IEnumerable<string>de um método declarado para retornar, IEnumerable<object>por exemplo.
A contravariância é mais difícil de dar exemplos concretos de uso de interfaces, mas é fácil com um delegado. Considere Action<T>- isso representa apenas um método que recebe um Tparâmetro. Seria bom ser capaz de converter perfeitamente e usar um Action<object>como um Action<string>- qualquer método que receba um objectparâmetro funcionará bem quando for apresentado com um string. Obviamente, C # 2 já tem covariância e contravariância de delegados até certo ponto, mas por meio de uma conversão real de um tipo de delegado para outro (criando uma nova instância) - consulte P141-144 para exemplos. C # 4 tornará isso mais genérico e (acredito) evitará a criação de uma nova instância para a conversão. (Em vez disso, será uma conversão de referência.)
Espero que isso esclareça um pouco - por favor, me avise se não fizer sentido!