Это относится ко всем неизменным типам. string
оказывается неизменным.
Чтобы изменить неизменяемый тип вне метода, вы должны изменить ссылку. Следовательно, ref
или out
должны иметь эффект вне метода.
Примечание. Стоит отметить, что в вашем примере вы вызываете конкретный случай, который не соответствует другому примеру: вы фактически указываете на другую ссылку, а не просто меняете существующую ссылку. Как отметил dlev (и сам Скит в моих комментариях), если вы сделали то же самое для всех других типов (например, val = new int[1]
), включая изменяемые, то вы "потеряете" свои изменения один раз метод возвращается, потому что они не произошли с одним и тем же объектом в памяти, если только вы не используете ref
или out
, как вы использовали с string
выше.
Надеюсь, уточнить:
Вы передаете указатель, который указывает на ваш объект в памяти. Без ref
или out
создается новый указатель, который указывает на точно такое же местоположение, и все изменения происходят с использованием скопированного указателя. Используя их, используется тот же указатель, и все изменения, внесенные в указатель, отражаются вне метода.
Если ваш объект изменчив, то это означает, что он может быть изменен без создания нового экземпляра объекта. Если вы создаете новый экземпляр, вы должны указать на другое место в памяти, что означает, что вы должны изменить указатель.
Теперь, если ваш объект неизменен, то это означает, что его нельзя изменить без создания нового экземпляра.
В вашем примере вы создали новый экземпляр string
(равный "modified"
), а затем изменили указатель (input
), чтобы он указывал на этот новый экземпляр. Для массива int
вы изменили одно из 10 значений, на которые фактически указывает val
, что не требует вмешательства в указатель val
- оно просто идет туда, куда вы хотите (первый элемент массива ), а затем изменяет это первое значение на месте.
Более похожий пример (украденный из dlev, но это как сделать их действительно сопоставимыми):
static void Function(ref string input)
{
input = "modified";
}
static void Function2(int[] val)
{
val = new int[1];
val[0] = 100;
}
Обе функции изменяют указатель своего параметра. Только потому, что вы использовали ref
, input
«запоминает» свои изменения, потому что когда он изменяет указатель, он изменяет переданный указатель, а не просто его копию.
val
все еще будет массивом 10 int
s вне функции, а val[0]
будет все равно 1, потому что "val
" в Function2
является другим указатель, который первоначально указывает на то же местоположение, что и val
в Main, но указывает куда-то еще после создания нового массива (другой указатель указывает на новый массив, а исходный указатель продолжает указывать на то же место).
Если бы я использовал ref
с массивом int
, то он бы изменился. И он бы тоже изменился в размере.