Каково использование " ref " для переменных ссылочного типа В C#?

Я понимаю, что если я передаю значение типа (int, struct, etc.) в качестве параметра (без 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();
}

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

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 методов: при использовании 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#, я считаю, что это относится ко всем из них. Переменные (объекты) похожи на людей, живущих по некоторым адресам. Мы либо меняем людей, живущих по этим адресам, либо можем создать больше ссылок на людей, живущих по этим адресам в телефонной книге(сделать мелкие копии). Таким образом, более одного идентификатора может обратитесь по тому же адресу. Ссылочные типы хотят больше пространства, поэтому в отличие от типов значений, которые напрямую связаны стрелкой с их идентификатором в стеке, они имеют значение для другого адреса в куче( большее пространство для проживания). Это место нужно взять из кучи.

тип значения : Indentifier (содержит значение =адрес значения стека) - - - - - >значение типа значения

ссылочный тип: Идентификатор (содержит значение=адрес значения стека) - - - - >(содержит значение=адрес значение кучи) - - - - >значение кучи(чаще всего содержит адреса к другим значениям), представьте себе больше стрелок, торчащих в разных направлениях к массиву[0], массиву[1], массиву[2]

единственный способ изменить значение-следовать стрелкам. Если одна стрелка теряется / изменяется таким образом, что значение недоступно.


ссылочные переменные переносят адрес из одного места в другое, поэтому любое обновление на них в любом месте будет отражать все места, тогда что такое использование REF. Ссылочная переменная хороша до тех пор, пока не будет выделена новая память для ссылочной переменной, переданной в методе. Как только новая память выделит, то изменение значения на этом не будет отражаться везде. Для этого ref приходит. Ref-это ссылка ссылки, поэтому всякий раз, когда новая память выделяет ее, она узнает, потому что она указывает на это расположение поэтому значение может быть общим для всех. Вы можете увидеть изображение для большей ясности.

Ref in Reference Variable