Как строки передаются в .NET?

Когда я передаю string функции, является указателем на переданное содержимое строки или является ли вся строка передана функции в стеке как struct ?

Чтобы ответить на ваш вопрос, рассмотрите следующий код:

 void Main() { string strMain = "main"; DoSomething(strMain); Console.Write(strMain); // What gets printed? } void DoSomething(string strLocal) { strLocal = "local"; } 

Вам нужно знать три вещи, чтобы предсказать, что здесь будет происходить, и понять, почему это происходит.

  1. Строки являются ссылочными типами в C #. Но это только часть картины.
  2. Они также неизменяемы, поэтому в любое время вы делаете что-то похожее на то, что вы меняете строку, а вы нет. Создается совершенно новая строка, ссылка указывается на нее, а старая выбрасывается.
  3. Даже если строки являются ссылочными типами, strMain не передается по ссылке. Это ссылочный тип, но эта ссылка передается по значению . Это сложное различие, но это очень важно. Каждый раз, когда вы передаете параметр без ключевого слова ref (не считая параметров), вы передали что-то по значению.

Но что это значит?

Передача ссылочных типов по значению: вы уже это делаете

В C # существуют две группы типов данных: ссылочные типы и типы значений . Есть также два способа передать параметры в C #: по ссылке и по значению . Они звучат одинаково и легко путаются. Они не то же самое!

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

Вот первая строка нашего Main метода:

 string strMain = "main"; 

На этой строке есть две вещи: строка с main значением, хранящимся в памяти, и ссылочная переменная, называемая strMain указывающая на нее.

 DoSomething(strMain); 

Теперь мы передаем эту ссылку на DoSomething . Мы передали его по стоимости, поэтому это означает, что мы сделали копию. Но это ссылочный тип, поэтому мы скопировали ссылку, а не строку. Теперь у нас есть две ссылки, каждая из которых указывает на одно и то же значение в памяти.

Внутри вызываемого

Вот вершина метода DoSomething :

 void DoSomething(string strLocal) 

Нет ключевого слова ref , как обычно. Поэтому strLocal не strMain , но оба указывают на одно и то же место. Если мы «изменим» strLocal , вот так …

 strLocal = "local"; 

… мы не изменили сохраненную ценность как таковую. Мы повторно указали ссылку. Мы взяли ссылку под названием strLocal и нацелили ее на совершенно новую строку. Что происходит с strMain когда мы это делаем? Ничего. Он все еще указывает на старую струну!

 string strMain = "main"; //Store a string, create a reference to it DoSomething(strMain); //Reference gets copied, copy gets re-pointed Console.Write(strMain); //The original string is still "main" 

Неизменность важна

Давайте изменим сценарий на секунду. Представьте, что мы не работаем со строками, но с некоторым изменяемым ссылочным типом, например, с classом, который вы создали.

 class MutableThing { public int ChangeMe { get; set; } } 

Если вы ссылаетесь на ссылку objLocal на объект, на который указывает, вы можете изменить его свойства:

 void DoSomething(MutableThing objLocal) { objLocal.ChangeMe = 0; } 

В памяти все еще имеется только одно MutableThing , и как скопированная ссылка, так и исходная ссылка все еще указывают на нее. Свойства самого MutableThing изменились :

 void Main() { var objMain = new MutableThing(); objMain.ChangeMe = 5; Console.Write(objMain.ChangeMe); //it's 5 on objMain DoSomething(objMain); //now it's 0 on objLocal Console.Write(objMain.ChangeMe); //it's also 0 on objMain } 

Ах, но …

… строки неизменяемы! Нет свойства ChangeMe для установки. Вы не можете выполнить strLocal[3] = 'H'; как вы могли бы с массивом символов C-стиля; вам нужно построить целую новую строку. Единственный способ изменить strLocal – указать ссылку на другую строку, и это означает, что вы ничего не делаете, чтобы strLocal может повлиять на strMain . Значение неизменное, а ссылка – копия.

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

Дополнительные ресурсы:

  • Вот лучшая статья, которую я прочитал о различии между ссылочными типами и типами значений в C # , и почему ссылочный тип не совпадает с ссылочным параметром.
  • Как обычно, у Эрика Липперта также есть несколько отличных сообщений в блоге по этому вопросу .
  • У него тоже есть отличная работа по неизменности .

Строки в C # являются неизменяемыми ссылочными объектами. Это означает, что ссылки на них передаются (по значению), и после создания строки вы не можете ее изменить. Методы, которые производят модифицированные версии строки (подстроки, обрезанные версии и т. Д.), Создают измененные копии исходной строки.

Строки – это особые случаи. Каждый экземпляр является неизменным. Когда вы меняете значение строки, вы выделяете новую строку в памяти.

Таким образом, для вашей функции передается только ссылка, но когда строка редактируется, она становится новым экземпляром и не изменяет старый экземпляр.

  • Как заставить функцию СУММ в MySQL возвращать '0', если значения не найдены?
  • Как построить несколько функций на одной фигуре в Matplotlib?
  • Верхний уровень const не влияет на сигнатуру функции
  • Передача целочисленного значения по ссылке в Python
  • Вычисление перекрестного произведения двух векторов в Fortran 90
  • Есть ли способ использовать два оператора «...» в функции из R?
  • Почему C ++ не поддерживает функции, возвращающие массивы?
  • Передача функций в качестве аргументов в Matlab
  • Процедуры связанных типов передачи в качестве аргументов
  • Понимание разницы между f () и f (void) в C и C ++ раз и навсегда
  • Как подсчитать текст другого шрифта в excel
  • Interesting Posts

    Как получить места (например, газовые станции) вдоль маршрута между проездом и пунктом назначения в API Карт Google

    Не удалось установить жесткие диски в оболочку установщика Debian

    Mac-клавиатура для rm-файла

    Кэширование ответа HTTP

    использование пространства имен std; в файле заголовка

    Спящий / спящий режим Подтверждение экрана спящего / спящего режима?

    Почему свойство Set выбрасывает исключение StackOverflow?

    Установка Windows XP застряла на «пожалуйста, подождите …» с 500g HD

    Можно ли использовать SQL для построения таблицы данных Excel из других файлов Excel?

    Как преобразовать байт UTF-8 в строку?

    Как я могу изменить файл с шеф-поваром?

    Как заставить Excel (и другие продукты Microsoft Office) прекратить открытие файлов в одном приложении?

    Почему летучий определитель используется через std :: atomic?

    Виртуальный Wi-Fi без подключения к Интернету и / или совместимый сетевой адаптер?

    Остановить программы от автоматического запуска при загрузке в Windows

    Давайте будем гением компьютера.