=============
AKTUALIZACJA: Użyłem tej odpowiedzi jako podstawy dla tego wpisu na blogu:
Dlaczego parametry ref i out nie pozwalają na zmianę typu?
Więcej komentarzy na ten temat znajdziesz na blogu. Dzięki za świetne pytanie.
=============
Załóżmy, że masz zajęcia Animal
, Mammal
, Reptile
, Giraffe
, Turtle
i Tiger
, z oczywistych relacji podklasy.
Teraz przypuśćmy, że masz metodę void M(ref Mammal m)
. M
potrafi zarówno czytać, jak i pisać m
.
Czy możesz przekazać zmienną typu Animal
do M
?
Nie. Ta zmienna może zawierać a Turtle
, ale M
zakłada, że zawiera tylko ssaki. A Turtle
nie jest Mammal
.
Wniosek 1 : ref
parametrów nie można „zwiększyć”. (Jest więcej zwierząt niż ssaków, więc zmienna staje się „większa”, ponieważ może zawierać więcej rzeczy).
Czy możesz przekazać zmienną typu Giraffe
do M
?
Nie. M
Może pisać do m
i M
może chcieć napisać Tiger
do m
. Teraz wstawiłeś a Tiger
do zmiennej, która jest faktycznie typu Giraffe
.
Wniosek 2 : ref
parametrów nie można uczynić „mniejszymi”.
A teraz zastanów się N(out Mammal n)
.
Czy możesz przekazać zmienną typu Giraffe
do N
?
Nie. N
Może pisać do n
i N
może chcieć napisać Tiger
.
Wniosek 3 : out
parametrów nie można uczynić „mniejszymi”.
Czy możesz przekazać zmienną typu Animal
do N
?
Hmm.
Czemu nie? N
nie może czytać n
, może tylko pisać, prawda? Piszesz a Tiger
do zmiennej typu Animal
i wszystko gotowe, prawda?
Źle. Zasada nie brzmi: „ N
można tylko pisać n
”.
Zasady są w skrócie:
1) N
musi napisać n
przed N
powrotem normalnie. (Jeśli N
rzuca, wszystkie zakłady są anulowane.)
2) N
musi coś napisać, n
zanim coś przeczyta n
.
To pozwala na taką sekwencję wydarzeń:
- Zadeklaruj pole
x
typu Animal
.
- Przekaż
x
jako out
parametr do N
.
N
zapisuje Tiger
do n
, który jest aliasem dla x
.
- W innym wątku ktoś pisze
Turtle
do x
.
N
próbuje odczytać zawartość n
i Turtle
znajduje zmienną typu, jak uważa Mammal
.
Oczywiście chcemy uczynić to nielegalnym.
Wniosek 4 : out
parametrów nie można uczynić „większymi”.
Wniosek końcowy : Ani parametry, ref
ani out
parametry nie mogą różnić się typami. W przeciwnym razie należy złamać weryfikowalne bezpieczeństwo typów.
Jeśli te kwestie w podstawowej teorii typów Cię interesują, rozważ przeczytanie mojej serii o tym, jak działają kowariancja i kontrawariancja w C # 4.0 .