2013-11-24 3 views
3

Итак, как мы знаем, объекты (в текущем примере - строки) сравниваются относительно их ссылки в куче. Так, если:Сравнение строк в C#

string a = "something"; 
string b = "something"; 
bool isEqual = (a == b); 

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

string a = "somethingNew"; 
bool isEqual = (a == "somethingNew"); 

Как такие сравнения литералы, представленные в памяти (если вообще) и как весь процесс сравнения сделать в этом случае?

ответ

12

Объекты может быть сравнены по отношению к их ссылке в куче. Большинство объектов не были бы удобными для сравнения, если это так, как они были изначально использованы, и поэтому такие вещи, как string, фактически реализуют перегрузку операторов равенства, чтобы быть более интуитивными. string сравнивает равенство (через оператор равенства ==), сначала проверяя ссылку на память (сначала вызывая object.ReferenceEquals(object, object)), а если не та же ссылка, то возвращается к сравнению символов в строке, независимо от расположения памяти.

Строковые литералы, такие как "somethingNew", скомпилированы в переменную со ссылкой на это строковое значение в том, что .NET вызывает пул внутренней памяти ... Это средство, с помощью которого все строки с одинаковым значением (что означает один и тот же случай и символы) все служат указателями на единую ссылку в стажем пуле, а не на каждого, у которых есть собственное распределение памяти для идентичного значения. Это экономит память за счет поиска стоимости в пуле пользователя. Это работает, потому что строки неизменяемы (только для чтения), поэтому изменение значения строки посредством конкатенации с операторами + или += или иначе фактически создает совершенно новую строку. Строковые переменные не интернированы по умолчанию, если только они не являются литералами.

Сравнение строк в вашем примере будет успешным при проверке ссылки на исходный объект равенства и вернет true без дальнейшего анализа равенства. Это произойдет потому, что ваши переменные являются строковыми литералами и, таким образом, интернированы (имеют одинаковый адрес памяти). Если они не были интернированы, сравнение вернется к сопоставлению персонажей, опять же независимо от расположения памяти.

Вы можете стажер небуквальные строки вручную с помощью string.Intern(string)

+0

Я думаю, что это ** не ** действительно отвечает прямо на то, что ОП просит (последнее предложение). –

+0

Хорошая точка @KingKing - я добавлю к ней. – Haney

+2

Я понимаю, что все строки одного и того же значения будут указывать на одну и ту же ссылку (включая строковую константу), что означает, что второй пример OP будет проверять только ссылку, и он должен возвращать значение true. Чтобы создать новую ссылку того же значения, я думаю, что мы можем использовать 'string.Copy', а затем она будет возвращаться, чтобы сравнить все символы, как вы сказали. –

1

Это все еще тот же самый случай, вам не нужно иметь имя переменной для строкового литерала. Имейте в виду, что строка переопределяет оператор ==(), поэтому вы получаете сравнение по строке content, а не просто сравнение простого объекта. Так это работает точно так же:

string tail = "New"; 
bool isEqual = (a == "something" + tail); 
+1

Ссылка на объект ** не является несущественной для строки, поскольку она сначала пытается «закоротить» сравнение с проверкой объекта object.ReferenceEquals(). – Haney

+1

Вы раскалываете волосы, конечно, это позволяет оптимизировать сравнение. –

+3

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

5

Итак, как мы знаем, объекты (в данном примере - струнный) сравниваются по отношению к их ссылке в куче.

Неверно; оператор == может быть перегружен, и действительно перегружен для string.

Но что произойдет, если: используются

Сравнение строк; однако, даже если они не были: потому что эти данные поступают из литерала(), тот же экземпляр строки привел бы к в этом случае из-за «интернирования» - поэтому, даже если бы он использовал ссылочное сравнение, он все равно Работа.

0

У меня это получилось довольно запутанным, потому что информация, которую я получил по этой теме, была структурирована таким глупым способом, сначала объяснив, что сравнение между ссылочными типами осуществляется только только по их адресам, используя оператор '== '(все это было опубликовано в полужирным шрифтом с пояснениями о 4 страницах). Кроме того, все примеры были заданы строками, но не было ни единого слова о каком-либо значении равенства между ними. Итак, после публикации здесь, я решил закончить целую главу по делу и 3 страницы позже (на самом деле последнее предложение на последней странице) заявляло, что для «==» существует другое поведение при использовании для сравнения строки. Абсолютно идиотский. Итак, для окончательной проверки, чтобы убедиться, что у меня есть информация справа:

«==», используемый для строк, сначала проверяет, ссылаются ли обе переменные на один и тот же объект. Если нет, выполняется ли фактическое сравнение значений в самом содержимом.

Использование строковых констант как: bool isEqual = (a == "somethingNew"); для сравнения будет фактически получать постоянное значение, искать его в так называемом пуле, и если оно имеет совпадение, оно будет ссылаться на тот же объект? Значит, он фактически присваивает ему переменную? Извините, это все еще немного неясно для меня.

И последний (пример из данной статьи):

string firstString = "deer"; 
string secondString = firstString; 
string thirdString = "de" + 'e' + 'r'; 
cw(firstString == secondString); // True - same object 
cw(firstString == thirdString); // True - equal objects 
cw((object)firstString == (object)secondString); // True 
cw((object)firstString == (object)thirdString); //False 

не должны в этом случае значение thirdString искать в бассейне и всей переменной, чтобы получить ссылку на тот же объект, что и firstString и secondString?