2009-02-06 70 views
50

恐怕这是一个非常愚蠢的问题,但我必须错过一些东西。.NET中的System.String.Copy有什么用?

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

文档说该方法

创建具有 字符串的一个新实例相同的值指定的字符串。

由于字符串在.NET不可变的,我不知道什么是使用这种方法的好处,因为我认为

string copy = String.Copy(otherString); 

为所有实用目的似乎产生相同结果作为

string copy = otherString; 

也就是说,除了任何内部簿记这回事,复制了不ReferenceEquals到otherString的事实,有没有细微的差别 - 字符串是一个不可变类其平等基于价值而不是身份。 (感谢@Andrew野兔的指出我原来的措辞是不够准确的,表明我意识到有Copy ING,而不是之间的差异,但担心被认为缺乏有用差异的。)

当然,当通过null自变量时,Copy将抛出ArgumentNullException,并且“新实例”可能会消耗更多内存。后者似乎不是一种好处,而且我不确定空检查是否足够大以保证整个Copy方法。

谢谢。

+1

好吧,愚蠢的问题有很多投票ups ,, – TarunG 2011-07-03 05:10:51

回答

32

使用String.Copy您实际上正在分配新内存并将字符从一个字符串复制到另一个字符串;你会得到一个全新的实例,而不是让两个变量都是同一个实例。如果你使用非托管代码直接处理内存位置的字符串并且可以改变字符串,这可能很重要。

19

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

问:

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

答:

其实这是不正确的,如果您使用的门,你会在司机的座位告终。如果您使用驾驶员的侧门,则最终会进入驾驶员座位,如果您使用乘客的侧门,则最终会进入乘客座位。

现在在这个例子中,你可能会认为答案并不是真正的答案,因为问题是“乘客侧门的目的是什么?”。但是由于这个问题完全是基于对门的工作方式的错误概念,因此否定这种前提的驳斥将会通过扣除来揭示另一扇门的新目标?

+0

问题不是“它做什么”,而是“为什么我会用它?“ – 2009-02-06 16:23:10

+0

我认为关键是:”复制不可变信息的用途是什么?“而不是重新使用它。 – PhiLho 2009-02-06 16:23:16

+0

整个问题都是基于假设前提 ”string one = String.Copy(two);“和“string one = two;”是等价的语句,我只是简单地指出海报不正确。 – 2009-02-06 16:27:27

6
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指向的StringBuilder创建大小为100的缓冲。 (看看StringBuilder.ToString()方法内侧)


我觉得StringBuilder利用的String.Copy()和.NET Framework StringBuilder确实改变了string的内容是一部分。所以string并不总是不可变的。

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

自动更改检测?

-1

我不知道如何在.NET中实现字符串,但我认为Java是一个很好的参考。在Java中,新的String(str)也做了什么String.copy(str);做,分配一个新的字符串具有相同的值。

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

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

1

除了什么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的线程)。

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

13

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

如果使用关键字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 
5

通过BCL的.NET 4.0快速搜索显示,string.Copy方法被调用大约半打的地方。这些用法大致分为以下几类:

  1. 用于互操作的本机函数可能会损坏传入它们的字符串。如果您不能影响P/Invoke声明并且无法修复正在调用的函数,则string.Copy是最佳选择。

  2. 对于出于性能原因字符串被就地修改的情况。如果您需要在可能长的字符串中只将几个字符转换为小写字符,那么在不复制字符串两次并创建额外垃圾的情况下这样做的唯一方法是对其进行变异。

  3. 在看起来不必要的地方。很有可能一些程序员更习惯于Java或C++字符串,并没有意识到在C#中复制字符串很少有用。