在你的代碼打它...的順序
==
被覆蓋。這意味着調用缺省==
而不是"abc" == "ab" + "c"
作爲引用類型(它比較引用而不是值),它調用string.Equals(a, b)
。現在
,這個執行以下操作:
- 如果兩者確實是相同的,返回true。
- 如果其中任何一個都爲null,則返回false(如果它們都爲null,則返回true)。
- 如果兩者長度不同,則返回false;
- 通過一個字符串進行優化循環,將char-for-char與其餘字符進行比較(實際上int-for-int被視爲內存中的兩個整型塊,這是所涉及的優化之一)。如果達到最終結果時不失配,則返回true,否則返回false。
換句話說,它與類似的東西啓動:
public static bool ==(string x, string y)
{
//step 1:
if(ReferenceEquals(x, y))
return true;
//step 2:
if(ReferenceEquals(x, null) || ReferenceEquals(y, null))
return false;
//step 3;
int len = x.Length;
if(len != y.Length)
return false;
//step 4:
for(int i = 0; i != len; ++i)
if(x[i] != y[i])
return false;
return true;
}
除步驟4是一個基於指針的版本與展開循環應該因此理想地更快。我不會表明這一點,因爲我想談論整體邏輯。
有很大的捷徑。第一個是在步驟1中。因爲平等是自反的(身份需要相等,a == a
),那麼如果與自身相比,我們甚至可以在幾納米大小的情況下返回真實的納秒數。
步驟2不是一個捷徑,因爲它的一個條件必須進行測試,但請注意,因爲我們已經返回了真實的(string)null == (string)null
我們不需要另一個分支。所以調用的順序是快速的結果。
第3步允許兩件事。它既可以對不同長度的字符串進行快捷方式切換(總是爲假),也可以意味着在步驟4中不會意外拍攝超過一個字符串的末尾。
請注意,其他字符串比較不是這種情況,因爲例如WEISSBIER
和weißbier
的長度不同,但是大小寫不同,因此不區分大小寫的比較不能使用第3步。所有相等比較都可以執行第1步和第2步,因爲所使用的規則總是保持不變,所以您應該只使用它們有些人可以做第3步。
因此,雖然你錯誤地暗示它是引用而不是比較值,但確實將引用首先作爲非常重要的捷徑進行比較。還要注意,實習字符串(通過編譯放置在實習生池中的字符串或稱爲string.Intern
)將因此經常觸發此快捷方式。在您的示例代碼中就是這種情況,因爲編譯器在每種情況下都會使用相同的引用。
如果你知道一個字符串被攔截,你可以依賴這個(只是做引用相等性測試),但即使你不知道你可以從中受益(引用相等性測試將會至少縮短一些時間)。
如果你有一堆字符串,你會想經常測試它們中的某些字符串,但是你不想像內部一樣在內存中延長它們的壽命,那麼你可以使用XmlNameTable或者LockFreeAtomizer(很快將重命名爲ThreadSafeAtomizer,並且文檔已移至http://hackcraft.github.com/Ariadne/documentation/html/T_Ariadne_ThreadSafeAtomizer_1.htm--應該首先命名爲函數而不是實現細節)。
前者由XmlTextReader
在內部使用,因此也由System.Xml
的其餘部分使用,也可以被其他代碼使用。我寫的後者是因爲我想要一個類似的想法,這對於併發調用是安全的,對於不同類型,以及我可以重寫相等比較的位置。
在任何一種情況下,如果您放入50個全部爲「abc」的不同字符串,您將得到一個單獨的「abc」引用,允許其他垃圾收集。如果您知道發生了這種情況,您可以單獨依靠ReferenceEquals
,如果您不確定,那麼您仍然可以從捷徑中獲益。
@EricJ。但是如果他們確實有相同的內存地址,那麼**必須**具有相同的內容(畢竟它是*相同*實例)。 – Yuck 2012-01-18 17:06:32
@Yuck - 只有實習是規範的一部分,而不僅僅是實現細節。此外,單獨的應用程序域中的字符串可能是相同的並且具有不同的地址。 – psr 2012-01-18 19:04:50
@psr對,這就是爲什麼有條件檢查。如果引用是相同的,那麼你就完成了 - 就是這樣。否則,您必須比較每個變量的內容以確定邏輯相等。 – Yuck 2012-01-18 19:09:07