Вопрос

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

Почему кто-то может захотеть использовать Строка.Копировать (строка)?

В документации говорится, что метод

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

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

 string copy = String.Copy(otherString);

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

 string copy = otherString;

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

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

Спасибо.

Это было полезно?

Решение

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

Другие советы

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 эти ссылки указывают на одно и то же StringCopy функция возвращает новый String ссылка, которая имеет тот же Содержание но как другой объект в куче.


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

Вопрос:

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

Ответ:

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

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

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

Если вы закрепите строку с помощью 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

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

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

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

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

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 framework StringBuilderизменяет ли содержимое string.Таким образом, a string не всегда является неизменным.

В дополнение к тому, что сказал 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, будут заблокированы до завершения каждого из них, но они не будут мешать потокам, выполняющим ExampleMethod2).

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

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

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

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

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

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

Строка содержит символ[] со смещением и длиной в реализации.Если вы сделаете что-то вроде подстроки, это не будет выполнять копирование в память, но вернет новый экземпляр String, использующий тот же символ[].Во многих случаях этот шаблон позволит сэкономить много памяти при копировании и выделении.Однако, если вы подстрочите небольшой фрагмент внутри длинной большой строки.Он по-прежнему будет ссылаться на large 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[], чтобы предотвратить скрытую утечку / растрату памяти.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top