=============
AGGIORNAMENTO: ho usato questa risposta come base per questo post di blog:
Perché i parametri ref e out non consentono la variazione del tipo?
Vedi la pagina del blog per ulteriori commenti su questo problema. Grazie per l'ottima domanda.
=============
Supponiamo di avere classi Animal
, Mammal
, Reptile
, Giraffe
, Turtle
e Tiger
, con le relazioni sottoclasse evidenti.
Supponiamo ora di avere un metodo void M(ref Mammal m)
. M
può sia leggere che scrivere m
.
Puoi passare una variabile di tipo Animal
a M
?
No. Quella variabile potrebbe contenere un Turtle
, ma M
supporrà che contenga solo Mammiferi. A Turtle
non è un Mammal
.
Conclusione 1 : i ref
parametri non possono essere "ingranditi". (Ci sono più animali che mammiferi, quindi la variabile sta diventando "più grande" perché può contenere più cose.)
Puoi passare una variabile di tipo Giraffe
a M
?
No. M
può scrivere m
e M
potrebbe voler scrivere a Tiger
in m
. Ora hai inserito a Tiger
in una variabile che è in realtà di tipo Giraffe
.
Conclusione 2 : i ref
parametri non possono essere "più piccoli".
Adesso considera N(out Mammal n)
.
Puoi passare una variabile di tipo Giraffe
a N
?
No. N
può scrivere n
e N
potrebbe voler scrivere a Tiger
.
Conclusione 3 : i out
parametri non possono essere "più piccoli".
Puoi passare una variabile di tipo Animal
a N
?
Hmm.
Beh perchè no? N
non riesco a leggere n
, può solo scrivergli, giusto? Scrivi Tiger
a una variabile di tipo Animal
e sei pronto, giusto?
Sbagliato. La regola non è " N
può solo scrivere n
".
Le regole sono, brevemente:
1) N
deve scrivere n
prima di N
restituire normalmente. (Se N
viene lanciato, tutte le scommesse sono disattivate.)
2) N
deve scrivere qualcosa n
prima di leggere qualcosa da n
.
Ciò consente questa sequenza di eventi:
- Dichiarare un campo
x
di tipo Animal
.
- Passa
x
come out
parametro a N
.
N
scrive a Tiger
in n
, che è un alias per x
.
- Su un altro thread, qualcuno scrive a
Turtle
in x
.
N
tenta di leggere il contenuto n
e scopre a Turtle
in ciò che pensa sia una variabile di tipo Mammal
.
Chiaramente vogliamo renderlo illegale.
Conclusione 4 : i out
parametri non possono essere "ingranditi".
Conclusione finale : Né ref
né out
parametri possono variare i loro tipi. Fare altrimenti significa rompere la sicurezza verificabile del tipo.
Se questi problemi nella teoria dei tipi di base ti interessano, potresti leggere le mie serie su come funzionano la covarianza e la contravarianza in C # 4.0 .