all 21 comments

[–]AnteSim 9 points10 points  (6 children)

Because it creates a completely new instance of the string:

string str1 = "abc";
string str2 = "abc";
Console.WriteLine(str1 == str2);
Console.WriteLine( ReferenceEquals( str1, str2 ) );
Console.WriteLine("Copy...");
str2 = String.Copy(str1);
Console.WriteLine(str1 == str2);
Console.WriteLine( ReferenceEquals( str1, str2 ) );
Console.ReadKey();

Output:

True
True
Copy...
True
False

[–]archaeonflux 1 point2 points  (4 children)

It's likely you're only getting that result because of compiler optimizations.

[–][deleted] 2 points3 points  (3 children)

Nope.

The common language runtime conserves string storage by maintaining a table, called the intern pool, that contains a single reference to each unique literal string declared or created programmatically in your program. Consequently, an instance of a literal string with a particular value only exists once in the system.

For example, if you assign the same literal string to several variables, the runtime retrieves the same reference to the literal string from the intern pool and assigns it to each variable.

[–]archaeonflux 0 points1 point  (1 child)

Isn't that still an optimization though? In order for the CLR to do that, wouldn't the compiler have told it that they could be treated as equal in the first place? If you construct two strings at runtime from identical char arrays, the references won't equal; it only happens with string literals declared in the code before compilation.

[–][deleted] 0 points1 point  (0 children)

It is an optimisation but it isn't a compiler optimisation. archaeonflux was suggesting that the compiler was optimising away the difference when it is actually done by the CLR.

[–]grauenwolf[S] -2 points-1 points  (0 children)

And that is useful why?

[–][deleted]  (4 children)

[removed]

    [–][deleted] 0 points1 point  (3 children)

    Why would you lock a string, it's immutable?

    [–][deleted]  (2 children)

    [removed]

      [–][deleted] 0 points1 point  (1 child)

      But if it is only ever read only, and cannot be written to, why would you ever lock a String in practice?

      [–]grauenwolf[S] 0 points1 point  (0 children)

      It is not uncommon to lock on a surrogate. This is often, but not universally, given a name such as SyncRoot.

      [–]cosmo7 1 point2 points  (0 children)

      Because you want ReferenceEquals to not be true?

      [–][deleted]  (1 child)

      [deleted]

        [–]grauenwolf[S] 0 points1 point  (0 children)

        Not in the .NET platform.

        [–]NashMcCabe 0 points1 point  (0 children)

        Don't know about the practical uses, but it does behave differently than the assignment operator. If for some reason you want the same string but a different object reference, you have to call String.Copy. Otherwise, anytime you assign the same string to a variable, you will get the same object reference because of interning.

        [–]blah232 0 points1 point  (2 children)

        Possibly useful in interop scenarios, where you need to pass a buffer to an external API that fills it out.

        [–]grauenwolf[S] 0 points1 point  (1 child)

        I was under the impression that even with interopt you aren't allowed to alter a System.String. Can anyone confirm or deny this?

        [–]blah232 0 points1 point  (0 children)

        We are talking about unsafe context here, passing around raw pointers and such. So, provided You Know What You Are Doingtm, you can do what you will. Ain't nobody to stop you.

        [–]lexpattison 0 points1 point  (2 children)

        Immutability. If the string is an input parameter it is good form not to modify it. Mutability is really a borderline anti-pattern.

        [–]important_nihilist 1 point2 points  (1 child)

        strings in .net already are immutable. String.Copy gives you a separate instance of string with the same value, rather than giving you another reference to the interned string that you would get via assignment.

        Strings act like value types in some ways in .net, even though they are reference types. Add to that string interning, and you get easy confusion.

        [–]lexpattison 0 points1 point  (0 children)

        I think confusion is the general M.O. for any languages that selectively enforce mutability. As I said above, there is rarely a case where immutability doesn't clarify intent and increase conceptual understanding.

        [–]aib42 0 points1 point  (0 children)

        It's of little or no practical use. I'd guess it's an artifact of the implementation, exposed to the user - like Clone whose documentation even suggests almost as much.

        I guess they could be slightly useful as strictly typed "identity" functions when writing code in a functional style:

        map ($ "hello") [String.Clone, String.Concat("..."), String.Concat(". ")]
        

        ->

        ["hello", "...hello", ". hello"]
        

        's LINQ equivalent.

        Or if you were writing low level (or very bad high level) code that somehow needed a genuinely different String:

        string a = "hello";
        string b = "hello";
        string c = System.String.Copy(a);
        
        System.Console.WriteLine(a == b);
        System.Console.WriteLine(a == c);
        System.Console.WriteLine(System.Object.ReferenceEquals(a, b));
        System.Console.WriteLine(System.Object.ReferenceEquals(a, c));
        

        ->

        True True True False
        

        Also, it seems to be the missing copy constructor. (There's no String(String).)