2015-12-15 30 views
6

我有類似下面的代碼:可能出現的意外參考對比擔任意

this.Session[key] = "foo"; 

if ((this.Session[key] ?? string.Empty) == "foo") 
{ 
    //do stuff 
} 

這當然,創建一個「可能出現的意外參考對比擔任意」的局面。對此的解決方案在此處有詳細記錄,並且我已經知道該修復會在我看到代碼後立即將會話變量強制轉換爲string

但是,代碼是歲,從未改變,因爲它最初寫的。直到這個星期在我們的測試環境中,if語句評估爲真,執行//do stuff部分。這個錯誤的代碼仍然在我們的生產環境中按照預期工作。

這怎麼可能?這段代碼沒有任何理由應該像預期的那樣工作;但它確實並且仍然在生產中。那麼爲了使這段代碼不應該工作但是已經做了什麼改變,突然停止工作(或者更確切地說,應該像它應該有的那樣)?

+0

是否在測試環境中超出proc會話? –

+3

在這個問題中,我很困惑兩件事。首先,這個問題包含一個邏輯上的謬誤:代碼的行爲總是一樣的。它比較兩個參考的平等。如果它生成真的,那是因爲引用是相等的。如果它始終如一地產生,那麼引用是一致的。我不明白你在這裏感到困惑。其次,我不能在我的生活中弄清楚無效合併操作符在這裏意味着什麼。代碼的意思是「如果值爲空,比較空爲空」,但爲什麼?如果爲null,則該值已經不是「foo」! –

+0

'Session [key]'究竟是如何設置的?它與什麼相比?您在測試和生產環境中使用了什麼版本的.NET框架?這兩種環境之間必定存在一些差異,導致字符串實習的工作方式不同。您發佈的代碼使用2個字符串文字 - afaik這些將始終被攔截,除非在彙編級別關閉了interning。 –

回答

4

字符串「富」是interned。這意味着每次使用它時,都會引用同一個對象。

公共語言運行庫通過維護一個名爲intern池的表來保存字符串存儲,該表包含對程序中以編程方式聲明或創建的每個唯一文字字符串的單個引用。因此,具有特定值的文字串的實例僅在系統中存在一次。

例如,如果您分配相同的文字串幾個變量,運行時獲取相同的參考,從實習生池的文字字符串,並將其分配給每個變量。

這就是爲什麼object.ReferenceEquals("foo", "foo")爲true。

如果你做同樣的動態創建的字符串,它不會被拘留,並引用不等於

object str = new StringBuilder().Append("f").Append("oo").ToString(); // str = "foo" 
object.ReferenceEquals(str, "foo");         // false 

字符串實習可以工作不同,這取決於實現,這就是爲什麼你可以得到不同的行爲在通過引用比較字符串時在不同的環境中

+0

這將是很好,你還包括一個例子,如何做到「正確」(Object.Equals((this.Session [key] ?? string.Empty),「foo」)',使用Object.Equals檢查對於Equals函數的重載,當兩個對象都不是它們的真實類型和空值時都適用) –

+0

@ScottChamberlain這是糾正代碼的一種非常迂迴的方式。最直接的方法是將'Session [key]'強制轉換爲字符串並使用適當的字符串比較。 – phoog

+0

@phoog'Session [key]'可能或不可以保存'string'。我同意它最爲理智的程序將始終是相同的類型,但已經顯示遺留代碼已經出錯,所以我不知道是否可信任它將永遠不會在會話中存儲除字符串之外的任何內容變量。 –

2

你是幸運的,比較工作!在你的例子中,字符串「foo」是interned,即兩個字符串文字都存儲一次並且具有相同的引用。然而,如果兩個Foo的之一在另一組件被定義或被去串行化或代碼(例如string s = "f"; string t = s + "oo";)以某種方式構造,則引用可能不同。由於Session[key]被鍵入爲對象,因此將執行參考比較。

聚結是沒有必要的,但是鑄造是:

if ((string)Session[key] == "foo") { ... } // This will perform a textual comparison. 

你也可以寫這個(因爲Equals是多態):

if (Session[key].Equals("foo")) { ... } // This will perform a textual comparison. 

這是不夠的,比較2個字符串值,它們必須靜態輸入爲string以便作爲字符串進行比較。

相關,喬恩斯基特對這個問題非常有趣的帖子:https://stackoverflow.com/a/3678810/880990