#c_sharp #unsafe
Думаю всем известно что строки (System.String) неизменяемые по своей природе. Поэтому часто работа с такими методами, как string.ToUpper() и прочими, порождает новый объект, почти идентичный предыдущему. Я даже не хочу выяснять причины этого, у меня явно ума поменьше чем у ребят, которые придумали такую обертку над массивом Char, но все же изменить строки можно, как минимум через указатели. Написал такой расширяющий метод: public static unsafe String ToUpperUnsafe ( this String value ) { fixed ( Char* arrChr = value ) { for ( var i = 0 ; i < value.Length ; ++i ) { var temp = Char.ToUpper( value[ i ] ); arrChr[ i ] = temp; } } return value; } Как видно, на вход принимается один объект, изменяется и возвращается без клонирования. Вопрос в том, насколько это безопасно. Смотрел бегло исходники оригинального метода, там много всего, что я не понял, из-за этого возникла мысль, что в определенных ситуациях это может не прокатить. p.s. Кстати ванильный метод работает быстрей, зато этот выигрывает в памяти.
Ответы
Ответ 1
Так делать нельзя. Дело в том, что весь framework исходит из того, что строки неизменяемы. Поэтому, например, если вы поместите строку в HashSet, а потом измените её, вы потом не сможете её оттуда удалить (а вместе с вами и другие куски программы, находящиеся далеко от вас и не знающие, что вы сломали строку). Метод сортировки, который не учитывает, что у него из-под носа могут заменить значение, имеет право зациклиться бесконечно или вылететь по обращению к неправильному индексу. Представьте себе, что будет, если строка, которую вы ломаете, интернирована. Тогда каждый, у кого была строковая константа "abc", внезапно без предупреждения получит строковую константу "ABC": string lo = "abc", hi = "ABC"; string villain = "abc"; villain.ToUpperUnsafe(); Console.WriteLine(lo == hi); // true Представьте себе так же, что вы сломаете строку, которая является названием типа. Что произойдёт при попытке применить рефлексию? Словом, ваш метод привносит в язык undefined behavour, отсутствие которого выгодно отличало C# от C++. Вся эта катавасия, которую может устроить одна «маленькая» оптимизация, совершенно не стоит выгоды в несколько микросекунд.Ответ 2
Вопрос в том, насколько это безопасно. Да вообще небезопасно. Думаю всем известно что строки (System.String) неизменяемые по своей природе. ... Я даже не хочу выяснять причины этого Зря не хочешь. Представь всё, что записывается литералами. Это числа. В VB ещё даты. Всё это value-типы. int x = 50; x.Add(10); // Ну представим, что такой метод есть int y = 50; // Ну ты же не ждёшь, что теперь y равен 60? Аналогично со строками: string s = "abc"; s.ToUpper(); string t = "abc"; // Упс.. Твоя реализация сделает t = "ABC" По-моему, одного этого достаточно, чтобы никогда твой метод не использовать. А теперь, почему же reference-тип? Да это просто оптимизация - не надо копировать огромные строки при каждой передаче. Мы просто не меняем оригинал, поэтому семантически нет разницы между value и reference. А вот если мы хотим поменять, то надо создать новую строку.Ответ 3
Вы только что изобрели велосипед :), используя unsafe, вместо класса StringBuilder, созданный именно для представления изменяемых строк.
Комментариев нет:
Отправить комментарий