<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          .net 中的判等

          共 6250字,需瀏覽 13分鐘

           ·

          2021-06-18 04:28

          前言

          前幾天,同事在 .net 程序中,遇到一個(gè)很 “詭異” 的問題:明明兩個(gè)值是相等的,可偏偏卻不相等,這是怎么回事呢?

          初遇問題

          剛聽到這個(gè)問題時(shí),我是滿臉的不相信,怎么可能?但是親自調(diào)試一看,確實(shí)什么都相等,但確實(shí)返回的不相等。見鬼了?為了更近一步研究這個(gè)問題,我特意模仿原程序邏輯寫了一個(gè)簡單的測試程序。

          示例代碼

          using System.Collections.Generic;
          using System.Linq;

          namespace TestOperatorEqualEqual
          {
              class CClassTest
              {
                  public int data1;
                  public int data2;
              }

              class Program
              {
                  public static bool IsClassTestEqual(CClassTest lhs, CClassTest rhs)
                  {
                      return lhs == rhs;
                  }

                  static void Main(string[] args)
                  {
                      List<CClassTest> testList = new List<CClassTest>();
                      for (int idx = 0; idx < 100; ++idx)
                      {
                          testList.Add(new CClassTest { data1 = idx, data2 = idx+1 });
                      }

                      CClassTest target = new CClassTest{data1 = 50, data2 = 51 };
                      var bContained = testList.Any(item => { return IsClassTestEqual(item, target); });
                      System.Console.WriteLine(bContained ? "yes" : "no");
                      System.Console.ReadKey();
                  }
              }
          }

          明明存在相等項(xiàng)(data1== 50, data2 == 51),但是 Any 卻返回了 false。是不是很詭異?你能一眼看出上面程序的問題嗎?

          單純從 vs  中看源碼,通過調(diào)試查看,都看不出任何問題。怎么辦?一般從源碼看不出問題,就需要從更底層來看,對于 C++ 編寫的原生程序來說就是查看匯編代碼,對于 C# 編寫的程序,優(yōu)先查看 IL(Intermediate Language) 代碼。微軟提供了查看 IL 代碼的工具—— ildasm。

          ildasm

          可以使用 everything 在磁盤上搜索 ildasm 的位置。

          search-ildasm-result

          ildasm 界面中,通過 file -> open 打開需要查看的程序,然后找到需要查看的方法,如下圖:

          view-ildasm

          好家伙,直接調(diào)用了 ceq,看到這段 IL 代碼,我恍然大明白,原來是比較了兩個(gè)變量的地址!難怪即使兩個(gè)類的成員一模一樣,但是總返回 false 了!

          趕緊谷歌一下 .net operator== msdn,發(fā)現(xiàn)了官方說明,鏈接如下:https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/equality-operators。讀完發(fā)現(xiàn)自己讀書太少了!下圖截取自上面的官方文檔。

          reference-type-equality-msdn

          原來,== 對于引用類型來說(class),是比較兩個(gè)變量是否引用同一個(gè)對象,而不是比較兩個(gè)變量的成員是否相等。

          修復(fù)

          知道問題的本質(zhì)原因,修改起來就很簡單了。只需要按成員比較兩個(gè) CClassTest 實(shí)例的成員是否相等即可。

          關(guān)鍵函數(shù)修改如下:

          public static bool IsClassTestEqual(CClassTest lhs, CClassTest rhs)
          {
              return lhs.data1 == rhs.data1 && lhs.data2 == rhs.data2;
          }

          彩蛋

          既然文檔里說了可以重載 == operator,那么就重載一下唄。這樣就不用額外提供一個(gè)比較函數(shù)了,直接使用 rhs == rhs 這種形式的比較就可以了。于是我大筆一揮,寫下了如下代碼:

          class CClassTest
          {
              public int data1;
              public int data2;

              public static bool operator == (CClassTest lhs, CClassTest rhs)
              {
                  if (lhs == null && rhs == null)
                  {
                      return true;
                  }
                  else if (lhs != null && rhs != null)
                  {
                      return lhs.data1 == rhs.data1 && lhs.data2 == rhs.data2;
                  }
                  else
                  {
                      return false;
                  }
              }

              public static bool operator != (CClassTest lhs, CClassTest rhs)
              {
                  return !(lhs == rhs);
              }
          }

          你能看出上面代碼的問題嗎?

          對,上面的寫法會導(dǎo)致 stackoverflow

          stackoverflow

          那正確的寫法是什么樣的呢?

          正確的寫法如下:

          public static bool operator ==(CClassTest lhs, CClassTest rhs)
          {
              if ((object)lhs == null && (object)rhs == null)
              {
                  return true;
              }
              else if ((object)lhs != null && (object)rhs != null)
              {
                  return lhs.data1 == rhs.data1 && lhs.data2 == rhs.data2;
              }
              else
              {
                  return false;
              }
          }

          **說明:**高版本的 c# (應(yīng)該是 c# 7 開始支持的) 還支持使用 is 判斷一個(gè)變量是否為空。

          下面這種寫法更優(yōu)雅!if (lhs is null && rhs is null) ...

          源碼下載

          csdn: https://download.csdn.net/download/xiaoyanilw/18335150

          百度云盤鏈接: https://pan.baidu.com/s/1VmnqoflrbWXFjeQV7TrKTg 提取碼: dsqt

          總結(jié)

          • 每種語言都有自己獨(dú)特的規(guī)則,學(xué)習(xí)并適應(yīng),才能更好的使用它。

          • 多讀書!


          瀏覽 29
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产成人精品免费视频麻豆大全 | 1插菊花综合网 | aa一级免费视频 | AV软件在线免费观看 | 日韩A片在线免费观看 |