У меня есть этот код:
var a = "ab";
var b = string.Concat("a", "b");
Console.WriteLine(string.IsInterned(a)!=null); //True
Console.WriteLine(string.IsInterned(b)!=null); //True
Console.WriteLine(object.ReferenceEquals(a,b)); //False
Таким образом, строка a
— это время компиляции и по умолчанию интернирована. Второй, как я подозревал, должен вести себя так же, как и "a"+"b"
, который тоже будет интернирован. Кажется, это подтверждается методами string.IsInterned(string)
, которые оба возвращают True. Однако адрес в памяти другой, на что указывает возврат object.ReferenceEquals(object,object)
False
. Если обе строки интернированы, разве они не должны быть на самом деле одним и тем же объектом в таблице интернирования строк, то есть одной и той же ссылкой?
Хорошо, я согласен, IsIntenred не возвращает bool, но он все равно возвращает ту же строку, если ссылка на нее найдена в пуле стажеров, и ноль, если нет. Я просто сравниваю их с нулевым значением, поэтому на практике это означает, что если они не равны нулю, то они интернированы.
Примечание: возможно, обидно, что компилятор не интерпретирует string.Concat("a", "b")
как (буквально) "a" + "b"
, поскольку последний оценивается компилятором как литерал "ab"
«на практике это означает, что если они не равны нулю, то они интернированы» — нет, это неверно; это означает, что строка с тем же содержимым интернируется (и в качестве результата выдается этот интернированный экземпляр); но это не обязательно означает, что предоставленная вами строка сама по себе является экземпляром интернированной строки.
Нет, он не возвращает ту же строку (с точки зрения ReferenceEquals
, которая вас волнует). Если бы это было так, не было бы причин возвращать строку вместо логического значения.
Хорошо, теперь я понял, только что попробовал то же самое с новым System.Text.StringBuilder().Append("ab").ToString(), и поведение осталось прежним, оно проверяет содержимое, а не ссылку. сам. Спасибо за объяснение
Теперь попробуйте:
var c = string.IsInterned(b);
Console.WriteLine(ReferenceEquals(a, c)); // spoiler: True
Console.WriteLine(ReferenceEquals(b, c)); // spoiler: False
Он говорит вам: «Да, у меня есть интернированное значение, содержащее "ab"
» — но это не означает, что переданная вами ссылка сама является интернированной — просто содержимое "ab"
существует в интернированном списке.
«… методы string.IsInterned(string), которые оба возвращают True». Ну нет, они возвращают ненулевое значение. Прочтите документацию, чтобы понять, что это значит.