Меня всегда веселят .NET-разработчики, которые говорят, что они всё знают про строки. Не, ну есть и такие, которые действительно всё знают. Но обычно я с лёгкостью накидываю несколько вопросов, после которых мой собеседник теряет значительную долю уверенности в собственных знаниях. Предлагаю вам список из нескольких достаточно простых вопросов на знание типа System.String
.
-
Различаются ли по скорости сравнение строк нижнего регистра и верхнего регистра? Будет ли различаться время выполнения команд
"abc1" == "abc2"
и"ABC1" == "ABC2"
?
В FCL сравнение строк в верхнем регистре оптимизировано, в общем случае лучше всегда использовать верхний регистр. Но в данном примере команды выполнятся одинаково быстро: оптимизация затрагивает только специфические локали. -
Пусть у нас имеется массив различных строк. Может ли метод сортировки от раза к разу давать разные результаты?
Да, стандартная сортировка в .NET является неустойчивой, а значит, если мы, скажем, сортируем строки без учёта регистра, то строки"AAA"
и"aaa"
могут расположиться в любом порядке. -
Может ли
String.CompareTo
вернуть 0 для строк разной длины?
-
Могут ли две строки совпасть по методу
String.CompareTo
, но различаться по методуString.Equals
?
Да, т.к. по умолчаниюCompareTo
выполняется с учётом региональных стандартов, аEquals
— без. -
Является ли сравнение строк после приведения к верхнему или нижнему регистру эквивалентом сравнения строк без учёта регистра?
Нет, в некоторых локалях такой фокус может не сработать. См. The Turkey Test. -
Пусть у нас имеется две строки из маленьких латинских букв. Как их сравнить быстрее всего?
С использованиемStringComparison.Ordinal
, т.к. в данном случае нет необходимости учитывать регистр и региональные настройки. -
При форматировании даты (
DateTime.ToString()
) по умолчанию будет использоватьсяCurrentUICulture
илиCurrentCulture
?
CurrentCulture
, т.к. данный пример не имеет отношения к графическому интерфейсу пользователя. -
В чём разница между
string s = "Line1\nLine2";
иstring s = "Line1" + Environment.NewLine + "Line2";
Второй вариант является более универсальным, т.к. не зависит от платформы. -
Как включить в литеральную строку знак обратного слэша (
\
) без использования управляющей последовательности?
Нужно использовать verbatim string:@"\"
. -
Может ли код
Console.WriteLine("Hello");
вывести строку, отличную от"Hello"
при использование стандартного методаConsole.WriteLine
?
Да, если строка интернирована, а кто-то через неуправляемую память добрался до хеш-таблицы интернированных строк и изменил целевое значение. -
Если мы пометим сборку атрибутом
System.Runtime.CompilerServices.CompilationRelaxationsAttribute
с флагомCompilationRelaxations.NoStringInterning
из того же пространства имён, то значит ли это, что литеральные строки в этой сборке не будут интернироваться?
Нет. Спецификация ECMA гласит, что в этом случае CLR только может не интернировать все строки, но не обязана. Кроме того, мы всегда может заинтернировать строку через методString.Intern
-
Если мы всё-таки отключили механизм интернировать строк под данную версию CLR, а в коде литеральная строчка
"Hello"
встречается дважды, то сколько раз она будет встречаться в метаданных сборки?
Один. Интернирование строк происходит во время выполнения программы и не имеет отношения к метаданным. -
Будет ли происходить копирование символьного массива при вызове метода
StringBuilder.ToString()
?
В .NET 2.0: Нет, в новая строка будет ссылаться на тот же символьный массив, что и исходныйStringBuilder.
В .NET 4.0: Да, в этой версии платформы массив всегда копируется. -
Допустим, у нас имеется
StringBuilder
, хранящий строчку из трёх символов. Возможен ли сценарий, в котором при замене первого символа произойдёт выделение памяти под новый символьный массив?
Да, если предыдущим методом былStringBuilder.ToString()
, а используемая версия .NET меньше 4.0. -
Хранить в обычных строках секретные данные (например, пароль) нельзя, т.к. строка хранится в памяти в открытом виде, злоумышленники могут легко до неё добраться. Какими стандартными средствами можно защитить данные?
Нужно хранить строчку с использованием классаSecureString
. -
Может ли количество текстовых элементов (которые можно получить через
TextElementEnumerator
) строки отличаться от количество образующих еёchar
-символов?
Да, т.к. FCL поддерживает кодировки, использующие больше 16-ти разрядов: один текстовый элемент может определяться несколькимиchar
-символами.
Хорошие материалы для чтения:
Для StringBuilder устаревшие данные. В 4.0 StringBuilder.ToString всегда выделяет новый массив, из-за того, что StringBuilder хранит данные в chunk’ах.
ОтветитьУдалитьСпасибо за замечание, исправил.
УдалитьВот убивают такие "всезнайки"... : "а кто-то через неуправляемую память добрался до хеш-таблицы интернированных строк и изменил целевое значение."
ОтветитьУдалитьВопрос в том же ключе:
Можно ли задать значение поля пользовательского объекта значимого типа, помеченной атрибутом readonly, не используя конструктор?
Вообще говоря, да: клонируешь структуру, убираешь атрибут readonly, и используя небезопасный доступ к объекту по указателю, в коде преобразуешь указатель на структуру с полем только-для-чтения в указатель на клонированную-структуру-с-полем-для-чтения-записи.
ОтветитьУдалитьСогласен с вами, хороший вопрос. И я считаю, что обсуждение таких вопросов весьма полезно. Во-первых, разбираясь в таких вещах, вы начинаете лучше понимать платформу, с которой работаете. Во-вторых, такие моменты могут пригодиться, если вы будете заниматься вопросами безопасности приложения. Но я ни в коем случае не агитирую использовать подобные вещи повсеместно в продакш-коде. Просто это вещи, о которых не помешает знать.
Удалить