Как строки передаются в .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 # являются неизменяемыми ссылочными объектами. Это означает, что ссылки на них передаются (по значению), и после создания строки вы не можете ее изменить. Методы, которые производят модифицированные версии строки (подстроки, обрезанные версии и т. Д.), Создают измененные копии исходной строки.

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

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

  • Встроенная функция связи
  • Как сделать случайный цвет фона с помощью Swift
  • Процедура с аргументом фиктивного аргумента предполагаемой формы должна иметь явный интерфейс
  • Расширение существующей функции jQuery
  • Как изменить реализацию (обход) функции, объявленной извне
  • Как использовать функцию rand для создания чисел в определенном диапазоне?
  • Написание собственной функции квадратного корня
  • Функция Excel для создания SQL-подобных запросов в данных рабочего листа?
  • «Срок службы» строкового литерала в C
  • Синтаксис MySQL CREATE FUNCTION
  • C вызовы функции: Понимание правила «неявного int»
  • Давайте будем гением компьютера.