=============
ATUALIZAÇÃO: usei esta resposta como base para esta entrada do blog:
Por que os parâmetros ref e out não permitem variação de tipo?
Veja a página do blog para mais comentários sobre esse assunto. Obrigado pela ótima pergunta.
=============
Vamos supor que você tem aulas Animal
, Mammal
, Reptile
, Giraffe
, Turtle
eTiger
, com os relacionamentos subclassificação óbvias.
Agora, suponha que você tenha um método void M(ref Mammal m)
. M
pode ler e escrever m
.
Você pode passar uma variável do tipo Animal
para M
?
Não. Essa variável pode conter a Turtle
, mas M
assumirá que ela contém apenas mamíferos. A Turtle
não é a Mammal
.
Conclusão 1 : ref
parâmetros não podem ser "maiores". (Existem mais animais que mamíferos, a variável está ficando "maior" porque pode conter mais coisas.)
Você pode passar uma variável do tipo Giraffe
para M
?
Não M
pode escrever para m
, e M
pode querer escrever uma Tiger
em m
. Agora você colocou um Tiger
em uma variável que é realmente do tipo Giraffe
.
Conclusão 2 : os ref
parâmetros não podem ser "menores".
Agora considere N(out Mammal n)
.
Você pode passar uma variável do tipo Giraffe
para N
?
Não. N
Pode escrever para n
e N
pode querer escrever a Tiger
.
Conclusão 3 : os out
parâmetros não podem ser "menores".
Você pode passar uma variável do tipo Animal
para N
?
Hmm.
Bem, porque não? N
não pode ler n
, só pode escrever, certo? Você escreve a Tiger
para uma variável do tipo Animal
e está tudo pronto, certo?
Errado. A regra não é " N
só pode escrever para n
".
As regras são, brevemente:
1) N
tem que escrever n
antes de N
retornar normalmente. (Se N
jogar, todas as apostas estão desativadas.)
2) N
tem que escrever algo n
antes de ler algo n
.
Isso permite esta sequência de eventos:
- Declare um campo
x
do tipo Animal
.
- Passe
x
como um out
parâmetro para N
.
N
escreve a Tiger
into n
, que é um alias para x
.
- Em outro segmento, alguém escreve um
Turtle
para x
.
N
tenta ler o conteúdo de n
e descobre um Turtle
no que ele acha que é uma variável do tipo Mammal
.
Claramente, queremos tornar isso ilegal.
Conclusão 4 : os out
parâmetros não podem ser "maiores".
Conclusão final : Nem ref
nem out
parâmetros podem variar seus tipos. Fazer o contrário é quebrar a segurança do tipo verificável.
Se essas questões na teoria básica de tipos lhe interessam, considere ler minha série sobre como a covariância e a contravariância funcionam no C # 4.0 .