Пустая строка как частный случай?
Я прочитал тест Джона Скита, и мне было интересно, почему второй образец моего не будет работать, а первый-нет.
почему это дает true:
object x = new string("".ToArray());
object y = new string("".ToArray());
Console.WriteLine(x == y); //true
но этот не делает:
var k="k";
//string.intern(k); // doesn't help
object x = new string(k.ToArray());
object y = new string(k.ToArray());
Console.WriteLine(x == y); //false
я использую fw 4.5 с vs2010.
к счастью, у меня также установлен vs2005, те же результаты :

7 ответов:
вот сообщение в блоге Эрика Липперта, которое отвечает на ваш вопрос:интернировании строк и строки.Пусто.
он описывает подобную ситуацию:
object obj = "Int32"; string str1 = "Int32"; string str2 = typeof(int).Name; Console.WriteLine(obj == str1); // true Console.WriteLine(str1 == str2); // true Console.WriteLine(obj == str2); // false !?Итак, идея заключается в том, что интернирование не означает, что у вас будет только один экземпляр конкретного
string, даже когда он стажировался. по умолчанию интернируются только литералы времени компиляции. Это означает, что следующий код выведет так:var k1 = "k"; object k2 = "k"; Console.WriteLine(k1 == k2);но, если вы пытаетесь создать строку с
"k"содержание программно во время выполнения, например, с помощьюstring(char[])конструктора, называяToString()на объекте, используяStringBuilderи т. д. По умолчанию вы не получите интернированную строку. Этот печатает ложь;var k1 = "k"; object k2 = new string("k".ToCharArray()); Console.WriteLine(k1 == k2);почему? Потому что интернирование строк во время выполнения стоит дорого.
нет такой вещи как бесплатный обед.
(...)
короче, это в общем случае не стоит интернировать всех веревка.
и о другом поведении с пустой строкой:
некоторые версии .NET runtime автоматически интернируют пустую строку во время выполнения, некоторые нет!
обратите внимание, что на стажировке в новая строки во втором блоке кода тут сделать их равными.
var k="k"; object x = string.Intern(new string(k.ToArray())); object y = string.Intern(new string(k.ToArray())); Console.WriteLine(x == y); //trueпохоже, что он интернирует пустые строки автоматически, но непустые строки не интернируются, если они не сделаны явно (или это литеральные строки, которые всегда интернируются).
Я предполагаю, что да, пустые строки рассматриваются как особый случай и интернируются автоматически, вероятно, потому, что проверка такова тривиально, что это не добавляет никакого реального штрафа за производительность (мы можем с уверенностью сказать, что любая строка длины 0 является пустой строкой и идентична любой другой пустой строке-все остальные строки требуют от нас смотреть на символы, а не только длину).
в первом случае сравниваются 2 ссылки на один и тот же объект (
String.Empty). Звонюoperator==по 2objectпеременные вызывают их компарацию по ссылке и даютtrue.во втором случае получается 2 разных экземпляра класса string. Их эталонное сравнение дает
falseесли вы даете
stringтипxиyво втором случаеstring.operator==переопределение будет вызвано и сравнение даетtrueобратите внимание, что мы не занимайтесь интернированием строки непосредственно в обоих случаях. Строковые объекты, которые мы сравниваем создаются с помощью
string(char[])конструктор. По-видимому, этот конструктор предназначен для возврата значенияstring.Emptyполе при вызове с пустым массивом в качестве аргумента.ответ, опубликованный MarcinJuraszek относится к блог Липперта который обсуждает интернирование строк. Это сообщение в блоге обсуждает другой угловой случай использования класса string. Рассмотрим пример из блог упомянутого Липперта:
object obj = ""; string str1 = ""; string str2 = String.Empty; Console.WriteLine(obj == str1); // true Console.WriteLine(str1 == str2); // true Console.WriteLine(obj == str2); // sometimes true, sometimes false?!здесь мы видим, что назначение из пустого строкового литерала (
"") не гарантирует получение ссылки на статический readonly
моя гипотеза заключается в том, почему первый дает true, а второй дает false:
первый результат моей оптимизации, возьмите следующий код code
Enumerable.Empty<char>() == Enumerable.Empty<char>() // trueИтак, предположим, что
ToArrayвозвращаетEnumerable.Empty<char>()когда строка пуста, это объясняет, почему первый результат дает true, а второй-нет, так как он выполняет проверку ссылок.
согласно http://msdn.microsoft.com/en-us/library/system.string.intern (v=vs. 110). aspx
In the .NET Framework 3.5 Service Pack 1, the Intern method reverts to its behavior in the .NET Framework 1.0 and 1.1 with regard to interning the empty string...
...In the .NET Framework 1.0, .NET Framework 1.1, and .NET Framework 3.5 SP1, ~empty strings~ are equalэто означает, что пустые строки интернируются по умолчанию, даже при построении из пустого массива, и поэтому равны.
кроме того:
The .NET Framework version 2.0 introduces the CompilationRelaxations.NoStringInterning enumeration memberэто, скорее всего, дает вам способ создать последовательный способ сравнения, хотя, как предполагает @BenM, вы бы достаточно явно использовать функцию стажера.
учитывая бокс, который происходит, вы также можете использовать
string.Equalsвместо==
Я думаю, что это может быть причиной, по которой я ссылаюсь Джон Скит ответ о сравнении строк
несколько строк.Равно () и == оператор действительно же?
object x1 = new StringBuilder("").ToString().ToArray(); object y1 = new StringBuilder("").ToString().ToArray(); Console.WriteLine(x1 == y1); //true Console.WriteLine("Address x1:" + Get(x1)); Console.WriteLine("Address y1:" + Get(y1)); var k = "k"; //string.intern(k); // doesn't help object x = new string(k.ToArray()); object y = new string(k.ToArray()); Console.WriteLine(x == y); //false Console.WriteLine("Address x:" + Get(x)); Console.WriteLine("Address y:" + Get(y)); Console.Read();выход
False Address x1:0x2613E5 Address y1:0x2613E5 False Address x:0x2613E5 Address y:0x2613E5
существует особый случай, когда пустые строки всегда возвращают один и тот же объект, и именно поэтому при сравнении, если объект одинаковый, в этом случае его истина.
[Edit]: предыдущий код использовал string comparator вместо object
object a = "s"; object b = "d"; a = ((string)a).Replace("s", ""); b = ((string)b).Replace("d", ""); Console.WriteLine(a == b); object c = "sa"; object d = "da"; c = ((string)c).Replace("s", ""); d = ((string)d).Replace("d", ""); Console.WriteLine(c == d); c = ((string)c).Replace("a", ""); d = ((string)d).Replace("a", ""); Console.WriteLine(c == d);результат
True False True
Comments