Что такое использование " ref " для переменных ссылочного типа В C#?
Я понимаю, что если я передаю тип значения (int, struct, и т.д.) в качестве параметра (без ключевого слова ref) в метод передается копия этой переменной, но если я использую ключевое слово ref, Ссылка на эту переменную передается, а не новая.
Но с ссылочными типами, такими как классы, даже без ключевого слова
ref, Ссылка передается методу, а не копии. Итак, каково использование ключевого слова ref с ссылочными типами?Принять за пример:
var x = new Foo();
В чем разница между следующим?
void Bar(Foo y) {
y.Name = "2";
}
И
void Bar(ref Foo y) {
y.Name = "2";
}
10 ответов:
Вы можете изменить то, что
fooуказывает на использованиеy:Foo foo = new Foo("1"); void Bar(ref Foo y) { y = new Foo("2"); } Bar(ref foo); // foo.Name == "2"
Есть случаи, когда требуется изменить фактическую ссылку , а не объект, на который указывают:
void Swap<T>(ref T x, ref T y) { T t = x; x = y; y = t; } var test = new[] { "0", "1" }; Swap(ref test[0], ref test[1]);
Джон Скит написал большая статья о передаче параметров в C#. Он четко описывает точное поведение и использование передаваемых параметров по значению, по ссылке (
ref) и по выходу (out).Вот важная цитата с этой страницы в отношении параметров
ref:Ссылочные параметры не передают значения переменных, используемых в вызов функциональных элементов-они используют сама переменная. Вместо того чтобы создание нового места хранения для переменная в элементе функции декларация, то же место хранения используется, поэтому значение переменной в члене функции и значении опорного параметра будет всегда быть одинаковым. Справочные параметры нужны модификатор ref в качестве участника декларация и призыв - вот что это значит, что всегда ясно, когда ты передавая что-то по ссылке.
Очень хорошо объяснено здесь : http://msdn.microsoft.com/en-us/library/s6938f28.aspx
Аннотация из статьи:
Переменная ссылочного типа не содержит своих данных непосредственно; она содержит ссылку на его данные. При передаче ссылочного типа параметр по значению, можно изменить данные, на которые указывает ссылка, например значение члена класса. Однако, вы невозможно изменить значение самой ссылки; то есть вы не могу используйте ту же ссылку, чтобы выделить память для нового класса и иметь его упорствуйте за пределами квартала. Для этого передайте параметр с помощью ключевое слово ref или out.
При передаче ссылочного типа с ключевым словом ref ссылка передается по ссылке, и вызываемый метод может присвоить параметру новое значение. Это изменение будет распространяться на область вызова. Без ref ссылка передается по значению, и этого не происходит.
C# также имеет ключевое слово 'out', которое очень похоже на ref, за исключением того, что с помощью' ref ' аргументы должны быть инициализированы перед вызовом метода, а с помощью 'out' вы должны назначить значение в получающем методе. метод.
Он позволяет изменять переданную ссылку. например
void Bar() { var y = new Foo(); Baz(ref y); } void Baz(ref Foo y) { y.Name = "2"; // Overwrite the reference y = new Foo(); }Вы также можете использовать out, Если вас не волнует ссылка, переданная в:
void Bar() { var y = new Foo(); Baz(out y); } void Baz(out Foo y) { // Return a new reference y = new Foo(); }
Еще одна куча кода
class O { public int prop = 0; } class Program { static void Main(string[] args) { O o1 = new O(); o1.prop = 1; O o2 = new O(); o2.prop = 2; o1modifier(o1); o2modifier(ref o2); Console.WriteLine("1 : " + o1.prop.ToString()); Console.WriteLine("2 : " + o2.prop.ToString()); Console.ReadLine(); } static void o1modifier(O o) { o = new O(); o.prop = 3; } static void o2modifier(ref O o) { o = new O(); o.prop = 4; } }
В дополнение к существующим ответам:
Как вы просили для различия 2 методов: нет никакой дисперсии co(ntra)при использовании
refилиout:class Foo { } class FooBar : Foo { } static void Bar(Foo foo) { } static void Bar(ref Foo foo) { foo = new Foo(); } void Main() { Foo foo = null; Bar(foo); // OK Bar(ref foo); // OK FooBar fooBar = null; Bar(fooBar); // OK (covariance) Bar(ref fooBar); // compile time error }
Параметр в методе, кажется, всегда передает копию, вопрос в том, копию чего. Копирование выполняется конструктором копирования для объекта, и поскольку все переменные являются объектами в C#, я полагаю, что это относится ко всем из них. Переменные (объекты) похожи на людей, живущих по некоторым адресам. Мы либо меняем людей, живущих по этим адресам, либо создаем больше ссылок на людей, живущих по этим адресам, в телефонной книге(делаем мелкие копии). Таким образом, несколько идентификаторов могут обратитесь по тому же адресу. Ссылочные типы требуют больше места, поэтому в отличие от типов значений, которые напрямую связаны стрелкой с их идентификатором в стеке, они имеют значение для другого адреса в куче( больше места для хранения). Это пространство должно быть взято из кучи.
Тип значения: Индентификатор (содержит значение =адрес значения стека) - - - - >значение типа значения
Тип ссылки: Идентификатор(содержит значение=адрес значения стека) - - - - >(содержит значение=адрес кучи значение) - - - - >значение кучи (чаще всего содержит адреса к другим значениям), представьте себе больше стрелок, торчащих в разных направлениях к массиву [0], массиву[1], массиву [2]
Единственный способ изменить значение-следовать стрелкам. Если одна стрелка потеряется / изменится таким образом, значение будет недоступно.
Ссылочные переменные переносят адрес из одного места в другое, поэтому любое обновление на них в любом месте отразится на всех местах, тогда в чем польза REF. Опорная переменная хороша до тех пор, пока не будет выделена новая память для опорной переменной, переданной в методе. Как только новую память выделят, то изменение значения на этом не отразится везде. Для этого ref приходит. Ref-это ссылка на ссылку, поэтому всякий раз, когда новая память выделяет ее, вы узнаете, потому что она указывает на это место поэтому ценность может быть разделена всеми. Вы можете увидеть изображение для большей ясности.

Comments