.NET中的System.String.Copy有什么用?

恐怕这是一个非常愚蠢的问题,但我一定会错过一些东西。

为什么要用String.Copy(string) ?

文档说明了这个方法

使用与指定的String相同的值创buildString的新实例。

由于string在.NET中是不可变的,所以我不确定使用这种方法有什么好处,就像我想的那样

string copy = String.Copy(otherString); 

对于所有的实际目的,似乎都会产生同样的结果

  string copy = otherString; 

也就是说,除了正在进行的内部簿记之外,以及事实上副本不是ReferenceEquals到otherString,没有可观察到的差异 – string是一个不可变的类,其相等性基于值而不是标识。 (感谢@Andrew Hare指出,我原来的措辞不够精确,不足以表明我意识到Copy和非Copy之间存在差异,但担心感觉缺乏有用的差异。)

当然,当传递一个null参数时,Copy抛出一个ArgumentNullException ,并且“新实例”可能消耗更多的内存。 后者似乎不是一个好处,我不确定这个空检查是一个足够大的奖金,以保证整个Copy方法。

谢谢。

有了String.Copy你实际上正在分配新的内存并将字符从一个string复制到另一个string。 你会得到一个全新的实例,而不是使两个variables都是同一个实例。 这可能会影响,如果你使用非托pipe代码的string直接处理内存位置,可以改变string。

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的问题。 我相信我是通过纠正问题本身的错误前提来回答这个问题的。 这是一个类似的(如果不是过于简单的)问题和答案,希望能够说明我的观点:

题:

我观察到,我的车有两个车门,一个在车的两边。 我相信,无论我使用哪扇门,我最终都会坐在驾驶座上。 另一扇门的目的是什么?

回答:

事实上,如果你使用任何一个门,你最终还是会坐在驾驶座上。 如果使用驾驶员的侧门,则最终进入驾驶座,如果使用乘客的侧门,则最终会进入乘客座位。

现在在这个例子中,你可能会认为答案不是真正的答案,因为问题是“乘客侧门的目的是什么?”。 但是,既然这个问题完全是基于对门的工作方式的错误认识,那么否定这个前提的驳斥将会通过推论来揭示另一个门的目的?

这是一个难题。 这并不能解释你为什么要这样做,但它确实有助于解释function差异。

如果使用fixed关键字fixedstring,则内容将是可变的。 在我头顶,我想不出你想要这样做的情况,但是这是可能的。

 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 
 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会占用更多的RAM,然后b ,指向StringBuilder创build的大小为100的缓冲区。 (看看StringBuilder.ToString()方法的内部)


我认为StringBuilder使用String.Copy()并作为.NET框架的一部分, StringBuilder确实改变了string的内容。 所以一个string并不总是不变的。

通过.NET 4.0的BCL快速search显示,在大约六个地方调用string.Copy方法。 用法大致分为以下几类:

  1. 与本地函数互操作,可能会损坏传递给它们的string。 如果您不能影响P / Invoke声明并且无法修复正在调用的函数, string.Copy是最好的select。

  2. 出于性能原因,对string进行就地修改的情况。 如果您需要在可能的长string中只将几个字符转换为小写字符,唯一的方法是在不复制string两次的情况下创build额外的垃圾信息就是改变它。

  3. 在似乎没有必要的地方。 一些程序员很可能更习惯于Java或C ++string,并没有意识到在C#中复制string很less有用。

除了什么tvanfosson说(我不认为你可以从非托pipe代码访问托pipestring使用的缓冲区…我知道这将是困难的,至less),我相信,如果string是可能有所不同用作对multithreadingfunction进行locking的对象。

例如…

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

我相信如果这两个示例方法并行运行,它们将locking相同​​的对象,因此一个将不能执行,而另一个在其locking块内。

但是,如果您将其更改为此…

 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的任何线程将被locking,直到每个完成,但他们不会干扰运行ExampleMethod2的线程)。

不知道这是一个有用的区别,因为有更好的同步机制(我不认为lockingstring是一个非常好的主意)。

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

自动更改检测?

我不知道如何在.NET中实现string,但我认为Java是一个很好的参考。

在Java中,新的String(str)也会做什么String.copy(str); 做,分配一个新的string具有相同的值。

这似乎没用,但在内存优化中非常有用。

String在实现中包含一个char [],偏移量和长度。 如果你做了一个子string,它不会做一个内存拷贝,但返回一个新的string实例共享相同的字符[]。 在很多情况下,这种模式会节省大量的内存拷贝和分配。 但是,如果你在一个很长的大string中对一小段子进行子串处理。 它仍然会引用大字符[],即使原来的大string也可以是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 []来防止隐藏的内存泄漏/浪费。