Проще говоря, ключевое слово ref
позволяет вызываемому методу манипулировать ссылкой на сайте вызова. Это полная цель ref
.
Что происходит, когда Vodka
возвращается, sss
заменяется новым экземпляром строки . Это не обновляет оригинальный экземпляр. Без модификатора ref
это невозможно.
Одна вещь, которую я часто нахожу в замешательстве, когда говорят об этом, это когда вы рассматриваете концепции передачи параметров по значению и по ссылке , когда вы имеете дело с ссылочные типы . Когда вы передаете строку (ссылочный тип) по значению , что на самом деле вы передаете? Вы передаете значение переменной. В этом случае значение является ссылкой на строку. Таким образом, вы передаете это значение, и вызывающий метод может использовать это значение для доступа к строке. Однако, поскольку параметр передается по значению, передается значение как таковое (по существу, копия ссылки), а не указатель на область памяти, в которой хранится значение. Вот почему вызывающий метод не может заменить экземпляр на сайте вызова.
При передаче параметра по ссылке вместо значения вызываемый метод получает доступ к области памяти, в которой хранится значение (имейте в виду, что значение является ссылкой на строку ). Это означает, что вызываемый метод может теперь обновить это значение, чтобы переменная на сайте вызова содержала ссылку на другую строку.
Обновление
Давайте разберем пример из вашего комментария (имена были изменены, чтобы защитить невинных):
class SomeClass
{
public int Value { get; set; }
}
class DoWork
{
public static void DoOne(SomeClass c) { c.Value = c.Value + 1; }
public static void DoTwo(ref SomeClass c) { c.Value = c.Value + 2; }
}
SomeClass
является ссылочным типом. Это означает, что любой фрагмент кода, которому вы передаете такой экземпляр (и, чтобы было ясно, мы никогда не передаем фактический экземпляр ссылочного типа, мы передаем ссылку в экземпляр), может манипулировать данные в этом случае *. Это означает, что он может вызывать методы, устанавливать значения свойств и т. Д., И любое изменение состояния, к которому это приводит, также видно на сайте вызовов. Ключевое слово ref
не влияет на это. Так что в вашем примере ключевое слово ref
не имеет значения. Однако учтите это изменение:
class DoWork
{
public static void DoOne(SomeClass c)
{
c = new SomeClass();
c.Value = 1;
}
public static void DoTwo(ref SomeClass c)
{
c = new SomeClass();
c.Value = 2;
}
}
Теперь давайте назовем это:
var temp = new SomeClass() { Value = 42 };
DoWork.DoOne(temp);
Console.WriteLine(temp.Value); // prints 42
DoWork.DoTwo(ref temp);
Console.WriteLine(temp.Value); // prints 2
Теперь происходит то, что оба метода создают новый экземпляр SomeClass
для работы. Поскольку DoOne
получает ссылку, переданную по значению, он обновит свою собственную частную копию ссылки, чтобы указать на новый экземпляр, и, естественно, это изменение не видно на сайте вызова.
С другой стороны, поскольку DoTwo
получает ссылку, переданную по ссылке , когда он создает новый экземпляр и присваивает ему c
, он обновляет ту же ячейку памяти, что и сайт вызова, использует поэтому temp
теперь ссылается на новый экземпляр, созданный внутри DoTwo
.
Подводя итог: для ссылочных типов вам нужно использовать ref
только в том случае, когда вы хотите разрешить вызываемому методу заменить сам переданный экземпляр . Если вы хотите манипулировать только состоянием этого экземпляра, ссылочные типы всегда позволят это.
Коди Грей опубликовал ссылку на параметр Джона Скита, передающий C # , если вы этого еще не сделали, прочитайте его. Он очень хорошо объясняет эти вещи (и даже больше; он также имеет дело с типами значений).
* (если тип не является неизменяемым, как строка, но это совсем другая история ...)