=============
ОБНОВЛЕНИЕ: я использовал этот ответ как основу для этой записи в блоге:
Почему параметры ref и out не допускают изменение типа?
См. Страницу блога для получения дополнительных комментариев по этому вопросу. Спасибо за отличный вопрос.
=============
Давайте предположим , что у вас есть классы Animal, Mammal, Reptile, Giraffe, Turtleи Tiger, с очевидными отношениями подклассов.
Теперь предположим, что у вас есть метод void M(ref Mammal m). Mможет читать и писать m.
Вы можете передать переменную типа Animalв M?
Нет. Эта переменная может содержать a Turtle, но Mпредполагается, что она содержит только Mammals. А Turtleне а Mammal.
Вывод 1 : refпараметры нельзя делать «больше». (Животных больше, чем млекопитающих, поэтому переменная становится «больше», потому что может содержать больше вещей.)
Вы можете передать переменную типа Giraffeв M?
Нет. Вы Mможете писать на m, а Mвозможно, захотите написать Tigerв m. Теперь вы поместили Tigerв переменную, которая на самом деле имеет тип Giraffe.
Вывод 2 : refпараметры нельзя делать «меньше».
Теперь посмотрим N(out Mammal n).
Вы можете передать переменную типа Giraffeв N?
Нет. NМожете написать nи, Nвозможно, захотите написать a Tiger.
Вывод 3 : outпараметры «меньше» делать нельзя.
Вы можете передать переменную типа Animalв N?
Хм.
А почему бы не? Nне может читать n, он может только писать, не так ли? Вы пишете Tigerпеременную типаAnimal и все готово, верно?
Неправильно. Правило не « Nможно только писать n».
Вкратце правила таковы:
1) Nдолжен выполнить запись nдо Nнормального возврата. (Если Nбросает, все ставки отменяются.)
2) Nдолжен что-то написать до nтого, как что-то прочитает n.
Это разрешает такую последовательность событий:
- Объявите поле
xтипа Animal.
- Передайте
xв качестве outпараметра N.
Nзаписывает Tigerв n, который является псевдонимом для x.
- В другом потоке кто-то записывает
Turtleв x.
Nпытается прочитать содержимое nи обнаруживает, Turtleчто он считает переменной типа Mammal.
Ясно, что мы хотим сделать это незаконным.
Вывод 4 : outпараметры нельзя делать «больше».
Окончательный вывод : Ни параметры, refни outпараметры не могут изменять свои типы. В противном случае нарушается безопасность проверяемого типа.
Если вас интересуют эти вопросы базовой теории типов, подумайте о прочтении моей серии статей о том, как ковариация и контравариантность работают в C # 4.0 .