Пустая строка как частный случай?



Я прочитал тест Джона Скита, и мне было интересно, почему второй образец моего не будет работать, а первый-нет.



почему это дает 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, те же результаты :



enter image description here

518   7  

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== по 2 object переменные вызывают их компарацию по ссылке и дают 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

    Ничего не найдено.