![](/img/trans.png)
[英]What is the difference between == and Equals() for primitives in C#?
[英]C# difference between == and Equals()
我在比較 2 個字符串的 silverlight 應用程序中有一個條件,由於某種原因,當我使用==
時它返回false而.Equals()
返回true 。
這是代碼:
if (((ListBoxItem)lstBaseMenu.SelectedItem).Content.Equals("Energy Attack"))
{
// Execute code
}
if (((ListBoxItem)lstBaseMenu.SelectedItem).Content == "Energy Attack")
{
// Execute code
}
為什么會發生這種情況?
當==
用於object
類型的表達式時,它將解析為System.Object.ReferenceEquals
。
Equals
只是一個virtual
方法並且行為如此,因此將使用覆蓋的版本(對於string
類型比較內容)。
將對象引用與字符串進行比較時(即使對象引用引用字符串),特定於字符串類的==
運算符的特殊行為將被忽略。
通常(即不處理字符串時), Equals
比較值,而==
比較對象引用。 如果您比較的兩個對象指的是一個對象的同一個實例,則兩者都將返回 true,但如果一個具有相同的內容並且來自不同的源(是具有相同數據的單獨實例),則只有 Equals返回真。 但是,正如注釋中所指出的,字符串是一種特殊情況,因為它覆蓋了==
運算符,因此在純粹處理字符串引用(而不是對象引用)時,即使它們是單獨的實例,也只會比較值。 以下代碼說明了行為的細微差別:
string s1 = "test";
string s2 = "test";
string s3 = "test1".Substring(0, 4);
object s4 = s3;
Console.WriteLine($"{object.ReferenceEquals(s1, s2)} {s1 == s2} {s1.Equals(s2)}");
Console.WriteLine($"{object.ReferenceEquals(s1, s3)} {s1 == s3} {s1.Equals(s3)}");
Console.WriteLine($"{object.ReferenceEquals(s1, s4)} {s1 == s4} {s1.Equals(s4)}");
輸出是:
True True True
False True True
False False True
==
和.Equals
都取決於實際類型中定義的行為和調用站點的實際類型。 兩者都只是方法/運算符,可以在任何類型上覆蓋並給出作者想要的任何行為。 根據我的經驗,我發現人們在對象上實現.Equals
而忽略實現 operator ==
是很常見的。 這意味着.Equals
將實際測量值的相等性,而==
將測量它們是否是相同的引用。
當我使用定義不斷變化的新類型或編寫泛型算法時,我發現最佳實踐如下
Object.ReferenceEquals
(一般情況下不需要)EqualityComparer<T>.Default
在某些情況下,當我覺得==
的用法有歧義時,我會在代碼中明確使用Object.Reference
equals 來消除歧義。
Eric Lippert 最近發表了一篇關於為什么 CLR 中有 2 種相等方法的主題的博客文章。 值得一讀
據我了解,答案很簡單:
==
比較對象引用。.Equals
比較對象內容。String
數據類型總是像內容比較一樣。我希望我是正確的,它回答了你的問題。
首先,是有區別的。 對於數字
> 2 == 2.0
True
> 2.Equals(2.0)
False
而對於字符串
> string x = null;
> x == null
True
> x.Equals(null)
NullReferenceException
在這兩種情況下, ==
比.Equals
我要補充一點,如果您將對象轉換為字符串,那么它將正常工作。 這就是為什么編譯器會給你一個警告說:
可能的意外參考比較; 要進行值比較,請將左側強制轉換為“字符串”
因為到目前為止還沒有提到.Equal
方法的靜態版本,我想在這里添加這個來總結和比較 3 個變體。
MyString.Equals("Somestring")) //Method 1
MyString == "Somestring" //Method 2
String.Equals("Somestring", MyString); //Method 3 (static String.Equals method) - better
其中MyString
是來自代碼中其他地方的變量。
背景信息和總結:
在 Java 中,不應使用==
來比較字符串。 如果您需要同時使用這兩種語言,我會提到這一點,並且讓您知道使用==
也可以用 C# 中更好的東西代替。
在 C# 中,使用方法 1 或方法 2 比較字符串沒有實際區別,只要它們都是字符串類型。 但是,如果一個為空,一個是另一種類型(如整數),或者一個表示具有不同引用的對象,那么,如最初的問題所示,您可能會遇到比較內容是否相等可能不會返回什么你期待。
建議的解決方案:
因為在比較事物時使用==
與使用.Equals
並不完全相同,所以您可以改用靜態 String.Equals方法。 這樣,如果兩側的類型不同,您仍然會比較內容,如果一個為空,您將避免異常。
bool areEqual = String.Equals("Somestring", MyString);
寫的多一點,但在我看來,使用起來更安全。
以下是從 Microsoft 復制的一些信息:
public static bool Equals (string a, string b);
參數
a
字符串
要比較的第一個字符串,或null
。
b
字符串
要比較的第二個字符串,或null
。
返回Boolean
如果a
的值與b
的值相同,則為true
; 否則為false
。 如果a
和b
都為null
,則該方法返回true
。
給答案補充一點。
.EqualsTo()
方法為您提供了與文化和區分大小寫進行比較的條件。
@BlueMonkMN 的早期答案還有另一個維度。 額外的維度是,@Drahcir 標題問題的答案也取決於我們如何獲得string
值。 為了顯示:
string s1 = "test";
string s2 = "test";
string s3 = "test1".Substring(0, 4);
object s4 = s3;
string s5 = "te" + "st";
object s6 = s5;
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s2), s1 == s2, s1.Equals(s2));
Console.WriteLine("\n Case1 - A method changes the value:");
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s3), s1 == s3, s1.Equals(s3));
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s4), s1 == s4, s1.Equals(s4));
Console.WriteLine("\n Case2 - Having only literals allows to arrive at a literal:");
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s5), s1 == s5, s1.Equals(s5));
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s6), s1 == s6, s1.Equals(s6));
輸出是:
True True True
Case1 - A method changes the value:
False True True
False False True
Case2 - Having only literals allows to arrive at a literal:
True True True
True True True
我在這里有點困惑。 如果 Content 的運行時類型是字符串類型,則 == 和 Equals 都應返回 true。 但是,由於情況似乎並非如此,因此內容的運行時類型不是字符串,並且對其調用 Equals 是在執行引用相等,這解釋了 Equals("Energy Attack") 失敗的原因。 然而,在第二種情況下,關於應該調用哪個重載 == 靜態運算符的決定是在編譯時做出的,這個決定似乎是 ==(string,string)。 這向我表明 Content 提供了到字符串的隱式轉換。
真的很棒的答案和例子!
我只想補充兩者之間的根本區別,
==
等運算符不是多態的,而Equals
是多態的
考慮到這個概念,如果您計算出任何示例(通過查看左手和右手引用類型,並檢查/知道該類型是否實際具有 == 運算符重載和 Equals 被覆蓋),您一定會得到正確的答案.
這是由於值相等(相等方法)和引用相等(== 運算符),因為相等方法檢查值,而相同的 == 檢查引用。
== 運算符覆蓋代碼在https://referencesource.microsoft.com/上的字符串類中可用
所以現在更容易理解了,equal 方法也有 2 個實現,一個來自字符串類本身,一個來自對象類。 它對性能的影響以及我還運行了一些基本代碼並嘗試了解基准測試。
我在下面分享結果請糾正或建議我是否在某處錯了。 有 3 個案例,我為所有案例運行了相同的代碼,這就是結果。
案例 1:這里我使用的是字符串。 用於比較 2 個字符串且兩個字符串具有相同值的 equal 方法。 string.equals(a,b)
第一次運行:5608195 滴答
第二次運行:5529387 滴答
第三次運行:5622569 滴答聲
總滴答數:16760151
情況 2:這里我使用的是字符串。 用於比較 2 個字符串並且兩個字符串具有相同值的 equal() 方法(重載一個)。 a.等於(b)
第一次運行:6738583 個滴答聲
第二次運行:6452927 個滴答聲
第三次運行:7168897 個滴答聲
總滴答數=20360407
情況 3:這里我使用 == 運算符來比較 2 個字符串,並且兩個字符串都具有相同的值。 a==b
第一次運行:6652151 個滴答聲
第二次運行:7514300 滴答
第三次運行:7634606 滴答
總滴答數=21801057
class Program
{
private static int count;
static string a = "abcdef";
static string b = "abcdef";
static void Main(string[] args)
{
for (int j = 1; j <= 3; j++)
{
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 1; i <= 1000; i++)
{
checkString();
}
sw.Stop();
Console.WriteLine(sw.ElapsedTicks);
}
Console.ReadLine();
}
public static void checkString()
{
for (int i = 1; i <= 100000; i++)
{
if (a==b)
count++;
}
}
}
C# 中的==
標記用於兩個不同的相等檢查運算符。 當編譯器遇到該標記時,它將檢查被比較的任一類型是否已為被比較的特定組合類型 (*) 或兩種類型都可以轉換為的類型組合實現了相等運算符重載。 如果編譯器發現這樣的重載,它將使用它。 否則,如果這兩種類型都是引用類型並且它們不是不相關的類(可能是接口,也可能是相關類),編譯器會將==
視為引用比較運算符。 如果兩個條件都不適用,編譯將失敗。
請注意,其他一些語言對兩個相等檢查運算符使用單獨的標記。 例如,在 VB.NET 中, =
標記在表達式中僅用於可重載的相等檢查運算符,而Is
用作引用測試或空測試運算符。 在不覆蓋相等檢查運算符的類型上使用=
將失敗,嘗試將Is
用於測試引用相等性或無效性以外的任何目的也會失敗。
(*) 類型通常只重載相等以與自身進行比較,但對於類型來說,重載相等運算符以與其他特定類型進行比較可能很有用; 例如, int
可以(恕我直言應該有但沒有)定義了一個相等的運算符來與float
進行比較,這樣 16777217 就不會報告自己等於 16777216f。 實際上,由於沒有定義這樣的運算符,C# 會將int
提升為float
,在相等檢查運算符看到它之前將其四舍五入為 16777216f ; 該運算符然后看到兩個相等的浮點數並將它們報告為相等,不知道發生的舍入。
Equals()
和==
是否相同取決於實現。 因為 C# 允許用戶分別為Equals()
和==
設置不同的行為。
class CompareTest
{
public readonly int val;
public CompareTest(int val)
{
this.val = val;
}
public override bool Equals(object obj)
{
return obj is CompareTest test && this.val == test.val;
}
public override int GetHashCode()
{
return val;
}
public static bool operator == (CompareTest a, object b)
{
return Equals(a, b);
}
public static bool operator != (CompareTest a, object b)
{
return !(a == b);
}
}
在此示例中,我使Equals()
和==
具有相同的行為。 但是如果我讓它們不同呢? 例如:
public static bool operator == (CompareTest a, object b)
{
return false;
}
Equals()
正常工作,但==
永遠不會工作。
此外,雖然我使它們具有相同的行為,但仍有一個區別:將調用哪個==
function 取決於左側的值:
Compare Test a = new CompareTest(1);
object b = new CompareTest(1);
CompareTest c = new CompareTest(1);
Debug.Log("AB " + (a == b)); // true
Debug.Log("BA " + (b == a)); // false! because it calls object's == function
Debug.Log("AC " + (a == c)); // true
Debug.Log("CA " + (c == a)); // true
當我們創建任何對象時,對象有兩個部分,一個是內容,另一個是對該內容的引用。 ==
比較內容和參考; equals()
只比較內容
http://www.codeproject.com/Articles/584128/What-is-the-difference-between-equalsequals-and-Eq
請注意,C# 中有兩種不同類型的相等性
1- Value Equality
(對於 int、DateTime 和 struct 等值類型)
2- Reference Equality
(對於對象)
有兩種基本的標准協議用於實現相等性檢查。
1- ==
和!=
運算符。
2- virtual
Equals
方法。
== 和 != 是靜態解析的,這意味着 C# 將在編譯時決定哪種類型將執行比較。
例如value-type
int x = 50;
int y = 50;
Console.WriteLine (x == y); // True
但對於reference type
object x = 50;
object y = 50;
Console.WriteLine (x == y); // False
Equals()
最初在運行時根據操作數的實際類型進行解析。
例如,在以下示例中,在運行時,將決定Equals()
將應用於 int 值,結果為true
。
object x = 5;
object y = 5;
Console.WriteLine (x.Equals (y)); // True
但是,對於引用類型,它將使用引用相等性檢查。
MyObject x = new MyObject();
MyObject y = x;
Console.WriteLine (x.Equals (y)); // True
請注意, Equals()
對struct
使用結構比較,這意味着它在結構的每個字段上調用 Equals。
==
== 運算符可用於比較任何類型的兩個變量,它只是比較位。
int a = 3;
byte b = 3;
if (a == b) { // true }
注意:int 的左側有更多的零,但我們在這里不關心。
int a (00000011) == 字節 b (00000011)
記住 == 運算符只關心變量中位的模式。
使用 == 如果兩個引用(原語)指向堆上的同一個對象。
無論變量是引用還是原始變量,規則都是相同的。
Foo a = new Foo();
Foo b = new Foo();
Foo c = a;
if (a == b) { // false }
if (a == c) { // true }
if (b == c) { // false }
a == c 為真 a == b 為假
a 和 c 的位模式相同,因此使用 == 時它們相等。
平等的():
使用 equals() 方法查看兩個不同的對象是否相等。
例如兩個不同的 String 對象,它們都代表“Jane”中的字符
Equal 和 == 之間的唯一區別在於對象類型比較。 在其他情況下,例如引用類型和值類型,它們幾乎相同(要么都是按位相等,要么都是引用相等)。
object: Equals: 按位相等 ==: 引用相等
字符串:(字符串的equals和==是一樣的,但是如果字符串中的一個變成了對象,那么比較結果就會不同) Equals: bit-wisequality == : bit-wisequality
有關更多解釋,請參見此處。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.