2009-02-06 12 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#中複製字符串很少有用。

相關問題