激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - C# - C#中的==運算符

C#中的==運算符

2022-01-11 14:05Sweet-Tang C#

這篇文章主要介紹了C#中的==運算符,非常不錯,具有參考借鑒價值,需要的朋友可以參考下

在這篇文章中,我們將介紹如下內容:

  • ==運算符與基元類型
  • ==運算符與引用類型
  • ==運算符與string類型
  • ==運算符與值類型
  • ==運算符與泛型

==運算符與基元類型

  我們分別用兩種方式比較兩個整數,第一個使用的是equals(int)方法,每二個使用的是==運算符:  

?
1
2
3
4
5
6
7
8
9
10
class program
{
  static void main(string[] args)
  {
    int num1 = 5;
   int num2 = 5;
    console.writeline(num1.equals(num2));
   console.writeline(num1 == num2);
 }
}

  運行上面的示例,兩個語句出的結果均為true。我們通過ildasm.exe工具進行反編譯,查看il代碼,了解底層是如何執行的。

C#中的==運算符

  如果您以前從來沒有接觸過il指令,不過沒關系,在這里您不需要理解所有的指令,我們只是想了解這兩個比較方式的差異。

  您可以看到這樣一行代碼:

?
1
il_0008: call    instance bool [mscorlib]system.int32::equals(int32)

  在這里調用的是int類型equals(int32)方法(該方法是iequatable<int>接口的實現)。

  現在再來看看使用==運算符比較生成的il指令:

?
1
il_0015: ceq

  您可以看到,==運行符使用的是ceq指令,它是使用cpu寄存器來比較兩個值。c#==運算符底層機制是使用ceq指令對基元類型進行比較,而不是調用equals方法。

==運算符與引用類型

  修改上面的示例代碼,將int類型改為引用類型,編譯后通過ildasm.exe工具反編譯查看il代碼。

?
1
2
3
4
5
6
7
8
9
10
11
12
class program
{
  static void main(string[] args)
  {
    person p1 = new person();
    p1.name = "person1";
    person p2 = new person();
   p2.name = "person1";
   console.writeline(p1.equals(p2));
   console.writeline(p1 == p2);
 }
}

  上述c#代碼的il代碼如下所示: 

C#中的==運算符

  我們看到p1.equals(p2)代碼,它是通過調用object.equals(object)虛方法來比較相等,這是在意料之中的事情;現在我們來看==運算符生成的il代碼,與基元類型一致,使用的也是ceq指令。

==運算符與string類型

   接來下來看string類型的例子:  

?
1
2
3
4
5
6
7
8
9
10
11
class program
 {
   static void main(string[] args)
   {
     string s1 = "sweet";
     string s2 = string.copy(s1);
     console.writeline(referenceequals(s1, s2));
     console.writeline(s1 == s2);
    console.writeline(s1.equals(s2));
  }
 }

  上面的代碼與我們以前看過的非常相似,但是這次我們使用string類型的變量。我們建一個字符串,并付給s1變量,在下一行代碼我們創建這個字符串的副本,并付給另一個變量名稱s2。

  運行上面的代碼,在控制臺輸出的結果如下:

C#中的==運算符

  您可以看到referenceequals返回false,這意味著這兩個變量是不同的實例,但是==運算符和equals方法返回的均是true。在string類型中,==運算符執行的結果與equals執行的結果一樣。

  同樣我們使用過ildasm.exe工具反編譯查看生成il代碼。

C#中的==運算符

  在這里我們沒有看到ceq指令,對string類型使用==運算符判斷相等時,調用的是一個op_equality(string,string)的新方法,該方法需要兩個string類型的參數,那么它到底是什么呢?

  答案是string類型提供了==運算符的重載。在c#中,當我們定義一個類型時,我們可以重載該類型的==運算符;例如,對于以前的例子中我們實現的person類,如果我們為它重載==運算符,大致的代碼如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class person
 {
   public string name { get; set; }
   public static bool operator ==(person p1, person p2)
  {
    // 注意這里不能使用==,否則會導致stackoverflowexception
    if (referenceequals(p1, p2))
       return true;
    if (referenceequals(p1, null) || referenceequals(p2, null))
      return false;
     return p1.name == p2.name;
   }
   public static bool operator !=(person p1, person p2)
   {
    return !(p1 == p2);
   }
 }

  上面的代碼很簡單,我們實現了==運算符重載,這是一個靜態方法,但這里要注意的是,方法的名稱是perator ==,與靜態方法的相似性;事實上,它們會被由編譯器成一個名稱為op_equality()的特殊靜態方法。

  為了使用事情更加清楚,我們查看微軟實現的string類型。

C#中的==運算符

  在上面的截圖中,我們可以看到,有兩個運算符的重載,一個用于相等,另一個是不等式運算符,其運算方式完全相同,但是否定等于運算符輸出。需要注意的一點是,如果您想重載一個類型的==運行符的實現,那么您還需要重載!=操作符的實現,否則編譯會報錯。

==運算符與值類型

   在演示值類型的示例前,我們先將person類型從引用類型改為值類型,person定義如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
public struct person
 {
   public string name { get; set; }
   public person(string name)
   {
     name = name;
   }
   public override string tostring()
   {
     return name;
   }
 }

  我們將示例代碼改為如下:

?
1
2
3
4
5
6
7
8
9
10
class program
 {
   static void main(string[] args)
   {
     person p1 = new person("person1");
     person p2 = new person("person2");
     console.writeline(p1.equals(p2));
     console.writeline(p1 == p2);
  }
}

   當我們在嘗試編譯上述代碼時,vs將提示如下錯誤:

C#中的==運算符

  根據錯誤提示,我們需要實現person結構體的==運算符重載,重載的語句如下(忽略具體的邏輯):

?
1
2
3
4
5
6
public static bool operator ==(person p1, person p2)
{
}
public static bool operator !=(person p1, person p2)
{
}

   當添加上面代碼后,重新編譯程序,通過ildasm.exe工具反編譯查看il代碼,發現值類型==運算符調用也是op_equality方法。

  關于值類型,我們還需要說明一個問題,在不重寫equals(object)方法時,該方法實現的原理是通過反射遍歷所有字段并檢查每個字段的相等性,關于這一點,我們不演示;對于值類型,最好重寫該方法。

==運算符與泛型

  我們編寫另一段示例代碼,聲明兩個string類型變量,通過4種不同的方式比較運算:

?
1
2
3
4
5
6
7
8
9
10
11
12
public class program
{
  public static void main(string[] args)
  {
    string str = "sweet";
    string str = string.copy(str);
    console.writeline(referenceequals(str, str1));
    console.writeline(str.equals(str1));
    console.writeline(str == str1);
    console.writeline(object.equals(str, str1));
 }
}

  輸出的結果如下:

  C#中的==運算符

  首先,我們使用referenceequals方法判斷兩個string變量都引用相同,接下來我們再使用實例方法equals(string),在第三行,我們使用==運算符,最后,我們使用靜態方法object.quals(object,object)(該方法最終調用的是string類型重寫的object.equals(object)方法)。我們得到結論是:

referenceequals方法返回false,因為它們不是同一個對象的引用;

string類型的equals(string)方法返回也是true,因為兩個string類型是相同的(即相同的序列或字符);

==運算符也將返回true,因為這兩個string類型的值相同的;

虛方法object.equals也將返回true,這是因為在string類型重寫了方法,判斷的是string是否值相同。

  現在我們來修改一下這個代碼,將string類型改為object類型:

?
1
2
3
4
5
6
7
8
9
10
11
12
public class program
{
  public static void main(string[] args)
  {
    object str = "sweet";
    object str = string.copy((string)str);
    console.writeline(referenceequals(str, str1));
    console.writeline(str.equals(str1));
    console.writeline(str == str1);
   console.writeline(object.equals(str, str1));
  }
}

  運行的結果如下:

C#中的==運算符

  第三種方法返回的結果與修改之前不一致,==運算符返回的結果是false,這是為什么呢?

  這是因為==運算符實際上是一個靜態的方法,對一非虛方法,在編譯時就已經決定用調用的是哪一個方法。在上面的例子中,引用類型使用的是ceq指令,而string類型調用是靜態的op_equality方法;這兩個實例不是同一個對象的引用,所以ceq指令執行后的結果是false。

  再來說一下==運算符與泛型的問題,我們創建一個簡單的方法,通過泛型方法判斷兩個泛型參數是否相等并在控制臺上打印出結果:

?
1
2
3
4
static void equals<t>(t a, t b)
{
  console.writeline(a == b);
}

  但是當我們編譯這段代碼時,vs提示如下錯誤:

C#中的==運算符

  上面顯示的錯誤很簡單,不能使用==運算符比較兩個泛型t。因為t可以是任何類型,它可以是引用類型、值類型,不能提供==運算符的具體實現。

  如果像下面這樣修改一下代碼:

?
1
2
3
4
static void equals<t>(t a, t b) where t : class
{
  console.writeline(a == b);
}

  當我們將泛型類型t改為引用類型,能成功編譯;修改main方法中的代碼,創建兩個相同的string類型,和以前的例子一樣:  

?
1
2
3
4
5
6
7
8
9
10
11
12
13
public class program
 {
   static void main(string[] args)
   {
     string str = "sweet";
     string str1 = string.copy(str);
     equals(str, str);
   }
   static void equals<t>(t a, t b) where t : class
   {
     console.writeline(a == b);
   }
 }

  輸出的結果如下:  

C#中的==運算符

  結果與您預期的結果不一樣吧,我們期待的結果是true,輸出的結果是false。不過仔細思考一下,也許會找到答案,因為泛型的約束是引用類型,==運算符對于引用類型使用的是引用相等,il代碼可以證明這一點:

C#中的==運算符

  如果我們泛型方法中的==運算符改為使用equals方法,代碼如下:  

?
1
2
3
4
static void equals<t>(t a, t b)
{
  console.writeline(object.equals(a, b));
}

  我們改用equals,也可以去掉class約束;如果我們再次運行代碼,控制臺打印的結果與我們預期的一致,這是因為調用是虛方法object.equals(object)重寫之后的實現。

  但是其它的問題來了,如果對于值類型,這里就會產生裝箱,有沒有解決的辦法呢?關于這一點,我們直接給出答案,有時間專門來討論這個問題。

  將比較的值類型實現iequatable<t>接口,并將比較的代碼改為如下,這樣可以避免裝箱:

?
1
2
3
4
static void equals<t>(t a, t b)
{
  console.writeline(equalitycomparer<t>.default.equals(a, b));
}

總結

  對于基元類型==運算符的底層機制使用的是ceq指令,通過cpu寄存器進行比較;

  對于引用類型==運算符,它也使用的ceq指令來比較內存地址;

  對于重載==運算符的類型,實際上調用的是op_equality這個特殊的方法;

  盡量保證==操作符重載和object.equals(object)虛方法的寫返回的是相同的結果;

  對于值類型,equals方法默認是通過反射遍歷所有字段并檢查每個字段的相等性,為了提高性能,我們需要重寫該方法;

  值類型默認情況下不能使用==運算符,需要實現==運算符的重載;

以上所述是小編給大家介紹的c#中的==運算符,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對服務器之家網站的支持!

原文鏈接:http://www.cnblogs.com/tdfblog/p/About-Equality-Operator-in-NET.html

延伸 · 閱讀

精彩推薦
  • C#深入解析C#中的交錯數組與隱式類型的數組

    深入解析C#中的交錯數組與隱式類型的數組

    這篇文章主要介紹了深入解析C#中的交錯數組與隱式類型的數組,隱式類型的數組通常與匿名類型以及對象初始值設定項和集合初始值設定項一起使用,需要的...

    C#教程網6172021-11-09
  • C#C#裁剪,縮放,清晰度,水印處理操作示例

    C#裁剪,縮放,清晰度,水印處理操作示例

    這篇文章主要為大家詳細介紹了C#裁剪,縮放,清晰度,水印處理操作示例,具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    吳 劍8332021-12-08
  • C#C#設計模式之Visitor訪問者模式解決長隆歡樂世界問題實例

    C#設計模式之Visitor訪問者模式解決長隆歡樂世界問題實例

    這篇文章主要介紹了C#設計模式之Visitor訪問者模式解決長隆歡樂世界問題,簡單描述了訪問者模式的定義并結合具體實例形式分析了C#使用訪問者模式解決長...

    GhostRider9502022-01-21
  • C#Unity3D實現虛擬按鈕控制人物移動效果

    Unity3D實現虛擬按鈕控制人物移動效果

    這篇文章主要為大家詳細介紹了Unity3D實現虛擬按鈕控制人物移動效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一...

    shenqingyu060520232410972022-03-11
  • C#WPF 自定義雷達圖開發實例教程

    WPF 自定義雷達圖開發實例教程

    這篇文章主要介紹了WPF 自定義雷達圖開發實例教程,本文介紹的非常詳細,具有參考借鑒價值,需要的朋友可以參考下...

    WinterFish13112021-12-06
  • C#C# 實現對PPT文檔加密、解密及重置密碼的操作方法

    C# 實現對PPT文檔加密、解密及重置密碼的操作方法

    這篇文章主要介紹了C# 實現對PPT文檔加密、解密及重置密碼的操作方法,非常不錯,具有參考借鑒價值,需要的朋友可以參考下...

    E-iceblue5012022-02-12
  • C#C#通過KD樹進行距離最近點的查找

    C#通過KD樹進行距離最近點的查找

    這篇文章主要為大家詳細介紹了C#通過KD樹進行距離最近點的查找,具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    帆帆帆6112022-01-22
  • C#C#實現XML文件讀取

    C#實現XML文件讀取

    這篇文章主要為大家詳細介紹了C#實現XML文件讀取的相關代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    Just_for_Myself6702022-02-22
主站蜘蛛池模板: 女人裸体让男人桶全过程 | 黄色片免费视频 | 91aa.app | 毛片av网| 1314成人网| 亚洲人成网站免费播放 | 久精品久久 | 亚洲极色 | 久久久成人一区二区免费影院 | 亚洲自拍第一 | 黄在线免费看 | 一级黄色性感片 | 黄视频免费在线观看 | 成人毛片100部 | 国产精品刺激对白麻豆99 | 免费午夜网站 | 成人久久免费 | 黄色免费影片 | 国产精品av久久久久久久久久 | 久久精品久久久久 | 国产乱淫av片免费 | 91一区二区在线观看 | 天天看天天摸天天操 | 精品一区二区在线播放 | 一级毛片电影网 | 福利免费观看 | 亚洲午夜一区二区三区 | 在线成人免费视频 | 欧美成人一区二区三区电影 | 国产美女的小嫩bbb图片 | 国产精品久久久久久婷婷天堂 | 国产一级免费视频 | 国产无遮挡裸体免费视频 | 久久精品性视频 | 精品一区二区三区免费毛片爱 | 斗破苍穹在线免费 | 黑人一区二区 | 国产自91精品一区二区 | 欧美性生活xxxxx| 国产一级一区二区三区 | 欧美日韩亚洲国产精品 |