String - Разница между клоном, копированием и стандартным воздействием

Я просто столкнулся с таким блоком, просматривая старый код:

object exeName = _connectionSettings.ApplicationName.Clone();
RandomFunction(exeName);

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

var copiedString = initialString;
var copiedString = initialString.Clone();
var copiedString = string.Copy(initialString);

Я создал базовый единичный тест, который, кажется, показывает, что нет ни одного, поскольку он ведет себя одинаково независимо от используемого метода (начальное аффектирование copyedString, изменение initialString, утверждение значения copiedString). Я что-то упускаю?

4 ответа

Использование Reflector для просмотра реализации String.Clone() показывает следующее:

public object Clone()
{
 return this;
}

Таким образом, ответ "Нет, нет никакой разницы между назначением и клонированием для строки".

Однако Copy() несколько отличается:

public static unsafe string Copy(string str)
{
 if (str == null)
 {
 throw new ArgumentNullException("str");
 }
 int length = str.Length;
 string str2 = FastAllocateString(length);
 fixed (char* chRef = &str2.m_firstChar)
 {
 fixed (char* chRef2 = &str.m_firstChar)
 {
 wstrcpy(chRef, chRef2, length);
 }
 }
 return str2;
}

Это фактически делает копию - но поскольку строки неизменяемы, это не очень полезно в любом случае.

Но - и это важно - Copy() вернет РАЗЛИЧНЫЕ ССЫЛКИ из исходной строки, а Clone() вернет SAME REFERENCE в качестве исходной строки.

Еще одна вещь, о которой нужно помнить, - это интернирование строк, которое приводит к тому, что строки с одинаковыми значениями обмениваются данными (и, следовательно, имеют одну и ту же строковую ссылку).

Например, следующий код напечатает "Same!":

string s1 = "Hello";
string s2 = "Hello";

if (ReferenceEquals(s1, s2))
 Console.WriteLine("Same!");

Но следующий код будет печатать "Не одинаково!", Хотя строковые значения одинаковы:

string s1 = "Hello";
string s2 = "He";
string s3 = "llo";
string s4 = s2 + s3;

if (!ReferenceEquals(s1, s4))
 Console.WriteLine("Not Same!");

Мы можем явно ставить s4, чтобы следующие отпечатки "То же!":

string s1 = "Hello";
string s2 = "He";
string s3 = "llo";
string s4 = s2 + s3;

s4 = string.Intern(s4);

if (ReferenceEquals(s1, s4))
 Console.WriteLine("Same!");


Поскольку CLR реализует неизменяемые строки и обрабатывает строки, подобные значениям, семантически, единственный раз, когда это было бы проблемой в правильном коде, находится вне изолированной программной среды с управляемым кодом, и даже в этом случае правильный код будет правильно рассматривать все аспекты строк CLR ( как и в 2 строках, может относиться к одному и тому же "значению").

В контексте управляемого кода строки должны быть просто назначены так же, как int и byte и float.


Поскольку CLR реализует неизменяемые строки и обрабатывает строки, подобные значениям, семантически, единственный раз, когда это будет проблемой в правильном коде, выходит за пределы изолированной программной среды с управляемым кодом.

В контексте управляемого кода строки должны быть просто назначены так же, как int и byte и float.


String.Clone() ничего не возвращает, но возвращает ссылку на одну и ту же строку (см. Здесь). Но поскольку строки в С# неизменны в любом случае, нет никакой разницы между всеми тремя указанными вами методами.

licensed under cc by-sa 3.0 with attribution.