Подтвердить что ты не робот

Что такое использование System.String.Copy в .NET?

Я боюсь, что это очень глупый вопрос, но я должен что-то упустить.

Почему можно использовать String.Copy(string)?

В документации указан метод

Создает новый экземпляр String с то же значение, что и указанная строка.

Так как строки неизменяемы в .NET, я не уверен, что польза от использования этого метода, поскольку я думаю, что

 string copy = String.Copy(otherString);

для всех практических целей, похоже, даст тот же результат, что и

 string copy = otherString;

То есть, за исключением того, что происходит внутренняя бухгалтерия, и тот факт, что копия не является ReferenceEquals для другойString, не существует различимых различий - String является неизменным классом, чье равенство основано на значении, а не на идентификаторе. (Спасибо @Andrew Hare за указание, что моя оригинальная фраза не была достаточно точной, чтобы указать, что я понял, что существует разница между Copy ing и нет, но она была обеспокоена отсутствием полезной разницы.)

Конечно, когда передано аргумент null, Copy выдает ArgumentNullException, а "новый экземпляр" может потреблять больше памяти. Последнее вряд ли похоже на пользу, и я не уверен, что нулевая проверка - достаточно большой бонус, чтобы гарантировать весь метод копирования.

Спасибо.

4b9b3361

Ответ 1

С String.Copy вы фактически выделяете новую память и копируете символы из одной строки в другую; вы получаете совершенно новый экземпляр, в отличие от того, что обе переменные являются одним и тем же экземпляром. Это может иметь значение, если вы используете строку с неуправляемым кодом, который напрямую связан с ячейками памяти и может изменять строку.

Ответ 2

String.Copy возвращает новый String и не дает те же результаты, что и

String copy = otherString;

Попробуйте следующее:

using System;

class Program
{
    static void Main()
    {
        String test = "test";
        String test2 = test;
        String test3 = String.Copy(test);

        Console.WriteLine(Object.ReferenceEquals(test, test2));
        Console.WriteLine(Object.ReferenceEquals(test, test3));

        Console.ReadLine();
    }
}

Когда вы устанавливаете test2 = test, эти ссылки указывают на тот же String. Функция Copy возвращает новую ссылку String, которая имеет такое же содержимое, но как другой объект в куче.


Изменить: Есть много людей, которые очень расстроены тем, что я не ответил на вопрос OP. Я считаю, что я ответил на этот вопрос, исправляя неправильную посылку в самом вопросе. Вот аналогичный (если не упрощенный) вопрос и ответ, который, надеюсь, проиллюстрирует мою мысль:

Вопрос:

Я заметил, что у моей машины две двери, по одной с каждой стороны машины. Я считаю, что правда, что независимо от того, какую дверь я использую, я закончу тем, что сижу на сиденье водителя. Какова цель другой двери?

Ответ:

На самом деле это неправда, если вы используете любую дверь, вы окажетесь на сиденье водителя. Если вы используете дверь со стороны водителя, вы окажетесь на сиденье водителя, и если вы используете дверь пассажира, вы окажетесь на пассажирском сиденье.

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

Ответ 3

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

Если вы привяжете строку с помощью ключевого слова fixed, содержимое будет изменяться. С головы до ног я не могу представить себе ситуацию, в которой вы хотели бы это сделать, но это возможно.

string original = "Hello World";
string refCopy = original;
string deepCopy = String.Copy(original);

fixed(char* pStr = original)
{
   *pStr = 'J';
}

Console.WriteLine(original);
Console.WriteLine(refCopy);
Console.WriteLine(deepCopy);

Вывод:

Jello World
Jello World
Hello World

Ответ 4

string a = "abc";
string b = String.Copy(a);

Monitor.Enter(a); // not the same as Monitor.Enter(b);

Однако

string c = "123";
string d = c;
Monitor.Enter(c); // the same as Monitor.Enter(d);

Что касается любого, кто будет заботиться, я думаю, что он существует для полноты.


Кроме

StringBuilder sb = new StringBuilder(100);
sb.Append("abc");
string a = sb.ToString();
string b = String.Copy(a);

Я думаю, что a займет больше ОЗУ, а затем b, так как a указывает на буфер размером 100, созданный StringBuilder. (Посмотрите на внутреннюю часть метода StringBuilder.ToString())


Я думаю, что StringBuilder использует String.Copy() и является частью платформы .NET StringBuilder изменяет содержимое string. Таким образом, string не всегда неизменен.

Ответ 5

Быстрый поиск по BCL для .NET 4.0 показывает, что метод string.Copy вызывается примерно в полдюжины мест. Эти обычаи подразделяются на следующие категории:

  • Для взаимодействия с собственными функциями, которые могут повредить переданные им строки. Если вы не можете повлиять на объявление P/Invoke и вы не можете исправить вызываемую функцию, лучшим выбором будет string.Copy.

  • В ситуациях, когда строка изменяется на месте по соображениям производительности. Если вам нужно преобразовать несколько символов в нижний регистр в потенциально длинную строку, единственный способ сделать это, не копируя строку два раза и создавая дополнительный мусор, - это изменить ее.

  • В тех местах, где это не представляется необходимым. Вполне возможно, что некоторые программисты более привыкли к строкам Java или С++ и не понимают, что копирование строки на С# редко бывает полезным.

Ответ 6

В дополнение к тому, что сказал tvanfosson (я не думаю, что вы можете получить доступ к буфере, используемому управляемой строкой из неуправляемого кода... Я знаю, что это будет сложно, по крайней мере), я считаю, что может быть разница, если строка используется как объект для блокировки для многопоточных функций.

Например...

using System;

public class Class1
{
    string example1 = "example";
    string example2 = example1;

    public void ExampleMethod1()
    {
        lock (example1)
        {
            Console.WriteLine("Locked example 1");
            //do stuff...
        }
    }

    public void ExampleMethod2()
    {
        lock (example2)
        {
            Console.WriteLine("Locked example 2");
            //do stuff
        }
    }
}

Я верю, что если два примера метода будут выполняться параллельно, они будут блокировать один и тот же объект, и, следовательно, никто не сможет выполнить, в то время как другой находится внутри блока блокировки.

Однако, если вы измените его на это...

using System;

public class Class1
{
    string example1 = "example";
    string example2 = string.Copy(example1);

    public void ExampleMethod1()
    {
        lock (example1)
        {
            Console.WriteLine("Locked example 1");
            //do stuff...
        }
    }

    public void ExampleMethod2()
    {
        lock (example2)
        {
            Console.WriteLine("Locked example 2");
            //do stuff
        }
    }
}

Тогда я считаю, что они будут блокировать выполнение других потоков, выполняющих один и тот же метод (т.е. любые потоки, выполняющие ExampleMethod1, будут заблокированы до тех пор, пока они не будут завершены, но они не будут мешать потокам, запущенным в примереMethod2).

Не уверен, что это полезная разница, так как есть лучшие механизмы синхронизации (я не думаю, что блокирующие строки - очень хорошая идея).

Ответ 7

string a = "test";
string b = a;
//Object.ReferenceEquals(a,b) is true
a += "more";
//Object.ReferenceEquals(a,b) is now false !

обнаружение автоматического изменения?

Ответ 8

Я не уверен, как String выполняется в .NET, но я думаю, что Java является хорошей ссылкой.

В Java новый String (str) также выполняет то, что String.copy(str); do, выделите новую строку с тем же значением.

Это кажется бесполезным, но оно очень полезно при оптимизации памяти.

Строка содержит char [] со смещением и длиной в реализации. Если вы сделаете что-то вроде подстроки, оно не будет делать копию памяти, но вернет новый экземпляр String, который будет использовать один и тот же char []. Во многих случаях этот шаблон сэкономит много памяти и распределения. Однако, если вы подстроить маленькую часть в длинной большой строке. Он по-прежнему будет ссылаться на большой char [], даже исходная большая строка может быть GC.

String longString = // read 1MB text from a text file
String memoryLeak = largeString.substring(100,102); 
largeString=null;
// memoryLeak will be sized 1MB in the memory
String smaller = new String(largeString.substring(100,102));
// smaller will be only few bytes in the memory

Он может заставить новый объект String выделить его char [], чтобы предотвратить утечку/отходы скрытой памяти.