Что такое использование " 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 147

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();
}

вы также можете использовать из если вы не заботитесь о ссылке, переданной в:

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 in Reference Variable