What's the use of System.String.Copy in .NET?

2019-02-01 15:33发布

I'm afraid that this is a very silly question, but I must be missing something.

Why might one want to use String.Copy(string)?

The documentation says the method

Creates a new instance of String with the same value as a specified String.

Since strings are immutable in .NET, I'm not sure what's the benefit of using this method, as I'd think that

 string copy = String.Copy(otherString);

would for all practical purposes seem to yield the same result as

 string copy = otherString;

That is, except for whatever internal bookkeeping that's going on, and the fact that copy is not ReferenceEquals to otherString, there are no observable differences - String being an immutable class whose equality is based on value, not identity. (Thanks to @Andrew Hare for pointing out that my original phrasing was not precise enough to indicate that I realized there was a difference between Copying and not, but was concerned about the perceived lack of useful difference.)

Of course when passed a null argument, Copy throws an ArgumentNullException, and the "new instance" might consume more memory. The latter hardly seems like a benefit, and I'm not sure that the null check is a big enough bonus to warrant a whole Copy method.

Thanks.

8条回答
贪生不怕死
2楼-- · 2019-02-01 16:09

I am not sure how String being implemented in .NET, but I think Java is a good reference.

In Java, new String(str) also do what String.copy(str); do, allocate a new String with same value.

It seem useless but it is very useful in memory optimization.

String contains a char[] with offset and length in the implementation. If you do a something like a substring, it won't do a memory copy but return a new String instance sharing same char[]. In many cases, this pattern will save a lot of memory copy and allocation. However, if you substring a small piece within a long large String. It will still reference to large char[] even the original large String is able to be 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

It can force the new String object allocate it's own char[] to prevent hidden memory leak/waste.

查看更多
等我变得足够好
3楼-- · 2019-02-01 16:22

In addition to what tvanfosson said (I don't think you can access the buffer used by a managed string from unmanaged code... I know it would be difficult, at least), I believe there may be a difference if the string is used as the object to do a lock on for multithreaded functionality.

For instance...

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
        }
    }
}

I believe if the two example methods are run in parallel, they will be locking the same object and thus one will not be able to execute while the other is inside its lock block.

However if you change it to this...

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
        }
    }
}

Then I believe they will only block execution of other threads executing the same method (i.e. any threads executing ExampleMethod1 will be locked until each completes, but they will not interfere with threads running ExampleMethod2).

Not sure this is a useful difference, since there are better mechanisms for synchronization (I don't think locking strings is a very good idea).

查看更多
Evening l夕情丶
4楼-- · 2019-02-01 16:23

String.Copy returns a new String and does not yield the same results as

String copy = otherString;

Try this:

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();
    }
}

When you set test2 = test these references point to the same String. The Copy function returns a new String reference that has the same contents but as a different object on the heap.


Edit: There are a lot of folks that are pretty upset that I did not answer the OP's question. I believe that I did answer the question by correcting an incorrect premise in the question itself. Here is an analogous (if not oversimplified) question and answer that will hopefully illustrate my point:

Question:

I have observed that my car has two doors, one on each side of the car. I believe it to be true that regardless of which door I use I will end up sitting in the driver's seat. What is the purpose of the other door?

Answer:

Actually it is not true that if you use either door you will end up in the driver's seat. If you use the driver's side door you will end up in the driver's seat and if you use the passenger's side door you will end up in the passenger's seat.

Now in this example you could argue that the answer is not really an answer as the question was "what is the purpose of the passenger's side door?". But since that question was wholly based on a misconception of the how the doors worked does it not follow that the refutation of the premise will shed new light on the purpose of the other door by deduction?

查看更多
孤傲高冷的网名
5楼-- · 2019-02-01 16:26
string a = "test";
string b = a;
//Object.ReferenceEquals(a,b) is true
a += "more";
//Object.ReferenceEquals(a,b) is now false !

auto-change detection ?

查看更多
混吃等死
6楼-- · 2019-02-01 16:29
string a = "abc";
string b = String.Copy(a);

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

However

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

As to way anyone will care, I think it is there for completeness.


Also

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

I think a will take up more RAM then b, as a points to the buffer of size 100 that the StringBuilder created. (Look at the inside of the StringBuilder.ToString() method)


I think StringBuilder makes use of String.Copy() and being part of the .NET framework StringBuilderdoes change the contents of the string. So a string is not always immutable.

查看更多
不美不萌又怎样
7楼-- · 2019-02-01 16:30

Here's one piece of the puzzle. It doesn't explain why you would want to do it, but it does help explain a functional difference.

If you pin the string using the fixed keyword, the contents would be mutable. Off the top of my head, I can't think of a situation in which you would want to do this, but it is possible.

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);

Output:

Jello World
Jello World
Hello World
查看更多
登录 后发表回答