Передача параметров ссылочного типа (руководство по программированию в C#)

Обновлен: Ноябрь 2007

Переменная ссылочного типа не содержит непосредственные данные; она содержит ссылку на эти данные. Если параметр ссылочного типа передается по значению, можно изменить данные, на которые указывает ссылка, например, значение члена класса. Однако нельзя изменить значение самой ссылки; то есть нельзя использовать одну ссылку для выделения памяти для нового класса и его создания вне заданного блока. Для этого передайте параметр с помощью ключевого слова ref или out. Для простоты в следующем примере использовано ключевое слово ref.

Пример

В следующем примере демонстрируется передача параметра ссылочного типа arr по значению в метод Change. Поскольку этот параметр является ссылкой на arr, можно изменить значения элементов массива. Однако попытка назначить параметр другому адресу в памяти может быть выполнена только внутри метода и не влияет на исходную переменную arr.

class PassingRefByVal 
{
    static void Change(int[] pArray)
    {
        pArray[0] = 888;  // This change affects the original element.
        pArray = new int[5] {-3, -1, -2, -3, -4};   // This change is local.
        System.Console.WriteLine("Inside the method, the first element is: {0}", pArray[0]);
    }

    static void Main() 
    {
        int[] arr = {1, 4, 5};
        System.Console.WriteLine("Inside Main, before calling the method, the first element is: {0}", arr [0]);

        Change(arr);
        System.Console.WriteLine("Inside Main, after calling the method, the first element is: {0}", arr [0]);
    }
}
/* Output:
    Inside Main, before calling the method, the first element is: 1
    Inside the method, the first element is: -3
    Inside Main, after calling the method, the first element is: 888
*/

В предыдущем примере массив arr, представляющий собой ссылочный тип, передается в метод без параметра ref. В этом случае в метод передается копия ссылки, указывающей на arr. В результате выполнения видно, что метод может изменить содержимое элемента массива, в данном случае с 1 на 888. Однако выделение новой области памяти с помощью оператора new внутри метода Change приводит к тому, что переменная pArray ссылается на новый массив. Поэтому любые изменения, внесенные после этого, не затрагивают исходный массив arr, созданный внутри Main. В действительности в данном примере создаются два массива, один внутри Main и один внутри метода Change.

Данный пример похож на предыдущий за исключением того, что здесь в заголовке метода и вызове используется ключевое слово ref. Любые изменения, выполняемые в методе, оказывают влияние на исходные переменные в вызывающей программе.

class PassingRefByRef 
{
    static void Change(ref int[] pArray)
    {
        // Both of the following changes will affect the original variables:
        pArray[0] = 888;
        pArray = new int[5] {-3, -1, -2, -3, -4};
        System.Console.WriteLine("Inside the method, the first element is: {0}", pArray[0]);
    }

    static void Main() 
    {
        int[] arr = {1, 4, 5};
        System.Console.WriteLine("Inside Main, before calling the method, the first element is: {0}", arr[0]);

        Change(ref arr);
        System.Console.WriteLine("Inside Main, after calling the method, the first element is: {0}", arr[0]);
    }
}
/* Output:
    Inside Main, before calling the method, the first element is: 1
    Inside the method, the first element is: -3
    Inside Main, after calling the method, the first element is: -3
*/

Все изменения, выполняемые внутри метода, влияют на исходный массив в Main. В действительности исходный массив перераспределяется с помощью оператора new. Поэтому после вызова метода Change любая ссылка на arr указывает на массив из пяти элементов, созданный в методе Change.

Перестановка строк представляет собой хороший пример передачи параметров ссылочного типа по ссылке. В данном примере две строки str1 и str2 инициализируются в Main и передаются в метод SwapStrings в качестве параметров, изменяемых по ключевому слову ref. Эти две строки переставляются внутри метода и также внутри Main.

 class SwappingStrings
 {
     static void SwapStrings(ref string s1, ref string s2)
     // The string parameter is passed by reference.
     // Any changes on parameters will affect the original variables.
     {
         string temp = s1;
         s1 = s2;
         s2 = temp;
         System.Console.WriteLine("Inside the method: {0} {1}", s1, s2);
     }

     static void Main()
     {
         string str1 = "John";
         string str2 = "Smith";
         System.Console.WriteLine("Inside Main, before swapping: {0} {1}", str1, str2);

         SwapStrings(ref str1, ref str2);   // Passing strings by reference
         System.Console.WriteLine("Inside Main, after swapping: {0} {1}", str1, str2);
     }
 }
 /* Output:
     Inside Main, before swapping: John Smith
     Inside the method: Smith John
     Inside Main, after swapping: Smith John
*/

В данном примере необходимо передать параметры по ссылке для оказания влияния на переменные в вызывающей программе. Если удалить ключевое слово ref как из заголовка метода, так и из вызова метода, то вызывающая программа изменена не будет.

Дополнительные сведения о строках см. в разделе Строка.

См. также

Основные понятия

Руководство по программированию в C#

Ссылки

Передача параметров (Руководство по программированию в C#)

Передача массивов при помощи параметров ref и out (руководство по программированию на C#)

ref (Справочник по C#)

Ссылочные типы (Справочник по C#)