1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        .net 中的判等

        共 6250字,需瀏覽 13分鐘

         ·

        2021-06-18 04:28

        前言

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

        初遇問題

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

        示例代碼

        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();
                }
            }
        }

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

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

        ildasm

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

        search-ildasm-result

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

        view-ildasm

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

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

        reference-type-equality-msdn

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

        修復

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

        關鍵函數修改如下:

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

        彩蛋

        既然文檔里說了可以重載 == operator,那么就重載一下唄。這樣就不用額外提供一個比較函數了,直接使用 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);
            }
        }

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

        對,上面的寫法會導致 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# (應該是 c# 7 開始支持的) 還支持使用 is 判斷一個變量是否為空。

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

        源碼下載

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

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

        總結

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

        • 多讀書!


        瀏覽 29
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            蜜乳AV一区二区三区天堂古代 | www.色色网.com | 水蜜桃视频在线观看 | 欧美中文字幕在线观看 | 双男主肉车文h | 黄色网页免费看 | 久久久久久九九九九 | 公交车上被摸出水 | 国产传媒免费 | 人人摸人人操人人 |