Обработка ссылочных типов - PullRequest
1 голос
/ 10 ноября 2009

Когда ссылочная переменная может быть передана по ссылке:

    class Example
    {
        public string str="Demo";

        public int[] intValues={1,3,4,5};

       public static void StrPassing(string someStr)
        {
            string otherStr="Changed!";
            someStr=otherStr;
        }

        public static void NumPassing(int[] a)
        {
            a[2] = 115;
        }

    }


       static void Main(string[] args)
        {
            Example ex = new Example();
            Example.StrPassing(ex.str);
            Example.NumPassing(ex.intValues);

            foreach (int i in ex.intValues)
            {
                Console.WriteLine(i);
            }

            Console.WriteLine(ex.str);
            Console.ReadLine();
        }

значение intValues[2] изменяется как 115 при передаче ссылки. Но значение строки "str" ​​(demo) не изменяется на "Changed!". В чем причина? могу ли я считать, что массивы передаются по ссылке, а другие ссылочные типы передаются по значение?

Ответы [ 4 ]

5 голосов
/ 10 ноября 2009

Все, что вы передаете методу в качестве аргументов, передается по значению, которое для ссылочных типов означает, что ссылка передается по значению. Таким образом, вы не можете изменить объект на другой, но вы, несомненно, можете изменить его содержимое (потому что это не меняет фактическую ссылку, просто немного памяти в другом месте).

Как показывает ваш пример с массивом, вы берете ссылку на массив (но не меняете ее) и меняете значение в массива. Это все равно что взять некоторый объект и изменить значение свойства. Вы можете сделать это просто изнутри метода тоже.

Если вы хотите изменить строку, которая является неизменным объектом в .NET, вам нужно прибегнуть к ref параметрам:

public static void StrPassing(ref string someStr)
{
    string otherStr="Changed!";
    someStr=otherStr;
}

И назовите это так:

string foo = "foo";
StrPassing(ref foo);
Console.WriteLine(foo); // should print "Changed!"

Ключевое слово ref гарантирует, что ваш метод получает фактическую ссылку на строку и может изменить ее, а не просто копию ссылки. Итак, вы можете заменить объект на совершенно новый.

Возвращаясь к вашему массиву: вам тоже будет непросто изменить переданный массив на совершенно другой массив:

public static void NumPassing(int[] a)
{
    a = new int[15];
}

тоже не сработает, потому что , тогда вы бы попробовали точно так же, как заменить строку на совершенно другую строку.

3 голосов
/ 10 ноября 2009

Вы должны различать изменение объекта, на который ссылается переменная , и изменение * содержимого объекта ".

В этом коде:

public static void StrPassing(string someStr)
{
    string otherStr="Changed!";
    someStr=otherStr;
}

... вы меняете значение someStr. Вы не вносите никаких изменений в строку, на которую изначально ссылается someStr. В самом деле, вы не можете, потому что строки неизменны. (Если бы это был StringBuilder, вы могли бы установить длину в 0, а затем добавить «Изменено!»)

Изменение значения someStr не имеет никакого эффекта, поскольку аргумент (ex.str) был передан по значению. (Рассматриваемое значение является ссылкой, но это не значит, что оно передано ссылкой .)

Теперь сравните это с этим кодом:

public static void NumPassing(int[] a)
{
    a[2] = 115;
}

Здесь вы не меняете значение a - вы изменяете содержимое массива, на который ссылается a.

Короче говоря, если вы не используете ref / out, аргументы будут передаваться по значению - но для ссылочных типов это значение является просто ссылкой.

У меня есть статья о передаче параметров , которая более подробно описывает все это.

1 голос
/ 10 ноября 2009

Что вам нужно сделать, это изменить подпись для StrPassing, чтобы она выглядела следующим образом:

public static void StrPassing(ref string someStr)
0 голосов
/ 10 ноября 2009

Строки являются особенными в C #. Они являются неизменяемыми ссылочными типами, что делает их поведение аналогичным типам значений.

Вот хорошая дискуссия.

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