=============
ACTUALIZACIÓN: Utilicé esta respuesta como base para esta entrada de blog:
¿Por qué los parámetros ref y out no permiten la variación de tipo?
Consulte la página del blog para obtener más comentarios sobre este tema. Gracias por la gran pregunta.
=============
Supongamos que usted tiene clases Animal
, Mammal
, Reptile
, Giraffe
, Turtle
y Tiger
, con las relaciones de subclases obvias.
Ahora suponga que tiene un método void M(ref Mammal m)
. M
Puede leer y escribir tanto m
.
¿Se puede pasar una variable de tipo Animal
a M
?
No. Esa variable podría contener a Turtle
, pero M
supondrá que solo contiene mamíferos. A Turtle
no es a Mammal
.
Conclusión 1 : los ref
parámetros no pueden hacerse "más grandes". (Hay más animales que mamíferos, por lo que la variable se está haciendo "más grande" porque puede contener más cosas).
¿Se puede pasar una variable de tipo Giraffe
a M
?
No. M
puede escribir m
y M
puede querer escribir un correo Tiger
electrónico m
. Ahora ha puesto una Tiger
variable en una variable que en realidad es de tipo Giraffe
.
Conclusión 2 : los ref
parámetros no pueden hacerse "más pequeños".
Ahora considera N(out Mammal n)
.
¿Se puede pasar una variable de tipo Giraffe
a N
?
No. N
puede escribir n
y N
puede querer escribir a Tiger
.
Conclusión 3 : los out
parámetros no pueden hacerse "más pequeños".
¿Se puede pasar una variable de tipo Animal
a N
?
Hmm
¿Bueno, por qué no? N
no puede leer n
, solo puede escribirle, ¿verdad? Escribes un Tiger
a una variable de tipo Animal
y estás listo, ¿verdad?
Incorrecto. La regla no es " N
solo se puede escribir n
".
Las reglas son, brevemente:
1) N
tiene que escribir n
antes de que N
vuelva normalmente. (Si N
lanza, todas las apuestas están canceladas).
2) N
tiene que escribir algo n
antes de que lea algo n
.
Eso permite esta secuencia de eventos:
- Declarar un campo
x
de tipo Animal
.
- Pase
x
como out
parámetro a N
.
N
escribe un Tiger
en n
, que es un alias para x
.
- En otro hilo, alguien escribe un
Turtle
en x
.
N
intenta leer el contenido de n
, y descubre un Turtle
en lo que piensa que es una variable de tipo Mammal
.
Claramente queremos que sea ilegal.
Conclusión 4 : los out
parámetros no pueden hacerse "más grandes".
Conclusión final : Ni ref
tampoco out
parámetros pueden variar sus tipos. Hacer lo contrario es romper la seguridad de tipo verificable.
Si estas cuestiones en la teoría básica de tipos le interesan, considere leer mi serie sobre cómo funcionan la covarianza y la contravarianza en C # 4.0 .