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

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

3 Solutions collect form web for “Как строки передаются в .NET?”

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

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

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

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

  • Перейти к определению функции в vim
  • Синтаксис MySQL CREATE FUNCTION
  • Разница между . и: в Луа
  • Почему размер массива не такой же, как и у основного?
  • Отправить форму при нажатии Enter с помощью AngularJS
  • strdup () - что он делает в C?
  • Имя таблицы как параметр функции PostgreSQL
  • Как реализована функция квадратного корня?
  • Зачем переходить по ссылке const вместо значения?
  • Разница между передачей массива и указателем на функцию в C
  • Как объяснить обратные вызовы на простом английском языке? Как они отличаются от вызова одной функции от другой функции?
  • Interesting Posts

    Выбор строк из фрейма данных на основе значений в векторе

    HTTP не смог зарегистрировать URL http: // +: 8000 / HelloWCF /. У вашего процесса нет прав доступа к этому пространству имен

    Как обрабатывать onContextItemSelected в операции с несколькими fragmentами?

    Как установить maxAllowedContentLength на 500 МБ во время работы на IIS7?

    Как остановить Outlook Out-Of-Office от ответа на определенные адреса?

    ISO C90 запрещает смешанные декларации и код в C

    Сообщение LogCat: Ресурсы служб Google Play не найдены. Проверьте конфигурацию проекта, чтобы убедиться, что ресурсы включены.

    Создание перестановок набора (наиболее эффективно)

    Почему мой компьютер колеблется, чтобы включить?

    Стиль прогрессивного WPF

    Как добавить аргументы командной строки (параметры) для закрепленных приложений в Windows 7?

    Установить операции (объединение, пересечение) в массиве Swift?

    versionCode vs versionName в Android Manifest

    Печать всех, кроме первых трех столбцов

    BroadcastReceiver не получает BOOT_COMPLETED

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