Какая польза от системы.Строка.Копия in.NET?


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

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

в документации сказано, что метод

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

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

 string copy = String.Copy(otherString);

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

 string copy = otherString;

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

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

спасибо.

8 52

8 ответов:

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


Edit: есть много людей, которые очень расстроены тем, что я не ответил на вопрос 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. Так что 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 !

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

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

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

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

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

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