Почему я не должен использовать небезопасный блок для изменения строки?

У меня есть строка, которую я хотел бы каким-то образом изменить. Например: отмените это или верните его.

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

Например:

        unsafe 
        {
            fixed (char* str = text)
            {
                *str = 'X';
            }
        }

Есть ли причины, почему я никогда не должен это делать?

Ответы

Ответ 1

. Framework.Net требует, чтобы строки были неизменными. Благодаря этому требованию он может оптимизировать все виды операций.

Интерпретация строк - один из величайших примеров этого требования, сильно зависит от него. Чтобы ускорить сравнение строк (и уменьшить потребление памяти),.NET Framework поддерживает словарь указателей, все предварительно определенные строки будут жить в этом словаре или в любых строках, где вы вызываете метод String.intern. Когда вызывается команда ldstr IL, она проверяет интернированный словарь и избегает выделения памяти, если у нас уже есть выделенная строка, обратите внимание: String.Concat будет не проверять интернированные строки.

Это свойство инфраструктуры .net означает, что если вы начнете трахаться напрямую со строками, вы можете повредить свою старую таблицу и, в свою очередь, повредить другие ссылки на одну и ту же строку.

Например:

         // these strings get interned
        string hello = "hello";
        string hello2 = "hello";

        string helloworld, helloworld2;

        helloworld = hello;
        helloworld += " world";

        helloworld2 = hello;
        helloworld2 += " world"; 

        unsafe
        {
            // very bad, this changes an interned string which affects 
            // all app domains.
            fixed (char* str = hello2)
            {
                *str = 'X';
            }

            fixed (char* str = helloworld2)
            {
                *str = 'X';
            }

        }

        Console.WriteLine("hello = {0} , hello2 = {1}", hello, hello2);
        // output: hello = Xello , hello2 = Xello  


        Console.WriteLine("helloworld = {0} , helloworld2 = {1}", helloworld, helloworld2);
        // output : helloworld = hello world , helloworld2 = Xello world  

Ответ 2

Есть ли причины, почему я никогда не должен это делать?

Да, очень просто: потому что .NET полагается на то, что строки неизменяемы. Некоторые операции (например, s.SubString(0, s.Length)) фактически возвращают ссылку на исходную строку. Если это теперь будет изменено, все остальные ссылки также будут сохранены.

Лучше использовать StringBuilder для изменения строки, поскольку это путь по умолчанию.

Ответ 3

Положите это так: как бы вы себя чувствовали, если другой программист решил заменить 0 на 1 в вашем коде во время выполнения? Он будет играть в ад со всеми вашими предположениями. То же самое относится к строкам. Все ожидают, что они будут неизменными и будут иметь в виду это предположение. Если вы нарушите это, вы, скорее всего, представите ошибки - и их будет очень сложно отслеживать.

Ответ 4

Боже мой, да.

1) Поскольку этот класс не предназначен для подделки.

2) Поскольку строки разработаны и ожидаются во всей структуре, чтобы быть неизменяемыми. Это означает, что код, который все остальные записывают (в том числе MSFT), ожидает, что значение строки не изменится.

3) Поскольку это преждевременная оптимизация, и это E V я L.

Ответ 5

Согласовано о StringBuilder или просто преобразует вашу строку в массив символов/байт и работает там. Кроме того, вы привели пример "upcasing" - класс String имеет метод ToUpper, и если это не так быстро, как ваш небезопасный "всплывающий", я буду есть шляпу.