2012-02-22 14 views
1

我剛纔寫的函數,我不明白爲什麼我得到的結果我:字符串表現得像一個值類型

private void ReplaceIfEmpty(string originalValue, string newValue) 
{ 
    if (string.IsNullOrWhitespace(originalValue)) 
    { 
    originalValue= newValue; 
    } 
} 

當我調用該函數的originalValue不會被更新。我的理解是一個字符串是一個類,因此它是一個引用類型,因此我傳入的值應該更新。你能解釋它爲什麼不是?

+0

可能的重複http://stackoverflow.com/questions/636932/in-c-why-is-string-a-reference-type-that-behaves-like-a-value-type – 2012-02-22 16:49:39

回答

19

此無關引用類型VS值類型真的。

你改變一個參數的值:

originalValue= newValue; 

對於不具備refout修改「正常」的參數,這種改變將永遠可見。

查看我的article on parameter passing瞭解更多信息,以及我的文章reference types and value types,以確保您理解爲什麼有時候它看起來像引用類型默認情況下是通過引用傳遞的。 (它們不是:所有參數默認都是按值傳遞的,只是對於引用類型而言,參數值是引用而不是對象,因此對調用者仍然可以看到對對象所做的更改。)

所以,你可以使一個originalValue參數ref - 但它會是更明智的方法返回一個string代替。我通常不願意使用ref參數;代碼是通常沒有它們更容易理解。

+0

+ 1說不要使用'ref' – Brian 2012-02-22 18:21:52

0

當你做對以下assignemnt:

originalValue = newValue; 

你不改變,是由originalValue引用的字符串值,你改變的originalValue價值指向同一位置newValue

字符串是不可變的,在設置後不能修改,只能重新分配。

+0

*是*改變'originalValue'的值 - 變量的值是一個引用,並且它將它改變爲一個不同的引用。但是,該更改對調用者不可見,因爲該參數是按值傳遞的。 – 2012-02-22 16:50:22

+0

@JonSkeet - 我的選擇不好。我指的是引用存儲的字符串值。試圖重新措詞的事情,使更清楚。自從我被吹出水面後,可能會被刪除。 – 2012-02-22 16:55:52

+0

不幸的是,這種事情的準確和易讀的措辭變得非常棘手:(當我談論對象時,我傾向於使用「object」這個詞(我認爲你的意思是「字符串值」)。 – 2012-02-22 16:58:16

5

你不改變,你作爲參數originalValue傳遞變量的值,你想一個新的實例分配給它,這對於引用意味着該變量指向一個新的參考 - 更新參考你需要通過裁判傳遞字符串 - 默認引用是按值傳遞,讓你通過永遠的變量被更新:

private void ReplaceIfEmpty(ref string originalValue, string newValue) 
{ 
    if (string.IsNullOrWhitespace(originalValue)) 
    { 
    originalValue = newValue; 
    } 
} 

更好的方法是隻返回,而不是新的字符串:

private string ReplaceIfEmpty(string originalValue, string newValue) 
{ 
    if (string.IsNullOrWhitespace(originalValue)) 
     return newValue; 
    else 
     return originalValue; 
} 

甚至更​​多方便使其擴展方法:

public static string ReplaceIfEmpty(this string originalValue, 
            string replaceValue) 
{ 
    if (string.IsNullOrWhitespace(originalValue)) 
     return replaceValue; 
    else 
     return originalValue; 
} 
7

您通過參考字符串。您沒有傳遞對變量的引用。如果你想改變一個變量然後你做這樣的:

private void ReplaceIfEmpty(ref string originalValue, string newValue) ... 

的差異經常混淆的人。這樣想一想。不要想象一串,想象兩個房子。現在想象兩張有這些房屋地址的紙張;那些是參考到房子。現在想象四個抽屜,每個抽屜都包含一張紙。抽屜標有p,q,x和y:

void M(House x, House y) 
{ 
    x = y; 
} 
... 
House p = new House("123 Sesame Street"); 
House q = new House("1600 Pennsylvania Avenue"); 
M(p, q); 

這個程序是做什麼的?你把一張紙放在抽屜裏寫上「123芝麻街」。你把一張紙放在抽屜裏寫上「1600 Pennsylvania Avenue」。

您在抽屜p中複印紙張並將複印件放入抽屜x中。您在抽屜q上覆印紙張並將複印件放入抽屜y中。然後你打電話給M. M把抽屜裏的東西複印一份,放在抽屜x裏。 抽屜p不受影響

現在考慮這種情況下:

void M(ref House r, House s) 
{ 
    r = s; 
} 
... 
House p = new House("123 Sesame Street"); 
House q = new House("1600 Pennsylvania Avenue"); 
M(ref p, q); 

這是什麼節目呢?你把一張紙放在抽屜裏寫上「123芝麻街」。你把一張紙放在抽屜裏寫上「1600 Pennsylvania Avenue」。

您在抽屜p上貼上一張便條,上面寫着「這個抽屜也被稱爲r」。

您在抽屜q中複印紙張並將複印件放入抽屜中。

然後你打電話給M. M把抽屜裏的東西複印一份,放在抽屜裏,這和抽屜p一樣。

有意義嗎?

+0

好的比喻,我會盡量記住,當我接下來必須向我的一個小輩解釋這個概念時。 – afrischke 2012-02-23 21:34:24