Outro dia me apresentaram o código abaixo com um dúvida bem boba. Esse código em C# abusa um pouco de uma das novidades da última revisão da linguagem, tipos genéricos variantes. Vamos ao código:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | interface A<in B> { } interface B<in A> { } class X : A<B<X>> { } class Y : B<A<Y>> { } class Test { static void Main () { A<Y> x = new X (); } } |
O código é um enrolado. A parte mais importante é entender interface A<in B> que é a declaração de A contravariante em B. Isso significa, a grosso modo, que A<object> instanceof A<string> == true.
A dúvida é se a atribuição A<Y> x = new X (); é válida. Vou usar <: como notação para
pode ser atribuido em, como em string <: object.
X <: A<Y> //X é uma classe e A uma interface, logo verificamos as interfaces de X A<B<X>> <: A<Y> //Duas instâncias diferentes do mesmo tipo genérico. Por ser contravariante no primeiro parâmetro, verificamos ele //Note que contravariância significa verificar na ordem inversa Y <: B<X> //Y é uma classe e B uma interface, logo verificamos as interfaces de Y B<A<Y>> <: B<X> //Novamente duas instancias de um tipo contravariante, verificamos o primeiro parâmetro X <: A<Y>
Calma la, voltamos a definição original! Sim, voltamos, existe um ciclo nessa verificação e ela não pode ser decidida. Tanto o compilador como o sistema de tipos são não capazes de decidir. A solução pragmática é simplesmente recusar essa atribuição.
Quem imaginaria que o novo sistema de tipos do C# possui casos que não decidíveis. Pois é, e não fica só nisso, existem outros problemas envolvendo variância como ambiguidade no caso de últimas interfaces que merecem outro artigo.
0 responses so far ↓
There are no comments yet...Kick things off by filling out the form below.
Leave a Comment