• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆 - 13, 文章 - 0, 評論 - 3, 引用 - 0
            數據加載中……

            Equals方法的實現(參見《Microsoft.net框架程序設計》并提出少許建議)

            從《Microsoft.net框架程序設計》一書中,看到Equals的實現基本分為如下三類(順序有所調整):
            (1)引用類型,從MyRefType到Object的繼承鏈上(基類、基類的基類、...),有類覆蓋了Object的Equals方法實現;
            (2)引用類型,從MyRefType到Object的繼承鏈上(基類、基類的基類、...),均沒有類覆蓋Object的Equals方法實現;
            (3)值類型的Equals方法實現。
            分法相當科學,不過我看了其中的代碼實現,針對第二種實現有一些自己的疑惑和想法。

            為了沒有看過該書的同仁們更好地理解,我將書中的實現貼在此文中。
            先看書中第一種,(1)引用類型,從MyRefType到Object的繼承鏈上(基類、基類的基類、...),有類覆蓋了Object的Equals方法的實現:

             1//引用類型,從MyRefType到Object的繼承鏈上(基類、基類的基類、),有類覆蓋了Object的Equals方法
             2    class MyRefType : BaseType
             3    {
             4        RefType refobj;     //該字段是一個引用類型
             5        ValType valobj;     //該字段是一個值類型
             6
             7        public override bool Equals(object obj)
             8        {
             9            //首先讓基類比較其中的字段
            10            if (!base.Equals(obj))
            11                return false;
            12
            13            //因為this不是null,所以如果obj是null,那兩個對象將不可能相等
            14            if (obj == null)
            15                return false;
            16
            17            //如果類型不同,不可能相等
            18            if (this.GetType() != obj.GetType())
            19                return false;
            20            //將obj轉型為定義的類型以訪問其中的字段。
            21            //注意這里的轉型不會失敗,因為已經知道兩個對象是同一個類型
            22            //obj的運行時類型要么是MyRefType,要么是MyRefType的子類
            23            MyRefType other = (MyRefType)obj;
            24
            25            //比較其中的引用類型字段
            26            //這里調用Object的static 方法Equals,是為了兼容考慮refobj或者other.refobj為null的情況
            27            if (!Object.Equals(refobj, other.refobj))
            28                return false;
            29
            30            //比較其中的值類型字段,
            31            //因為值類型不可能為null,所以直接調用值類型的Equals方法,免得裝箱的開銷
            32            if (!valobj.Equals(other.valobj))
            33                return false;
            34
            35            return true;    //到這里兩個對象才算相等
            36        }

            37    }

            其中用到了Object的Equals方法,將原代碼貼出來

             1    class Object
             2    {
             3        public virtual Boolean Equals(Object obj)
             4        {
             5            //如果兩個引用指向同一個對象
             6            //它們肯定相等
             7            if (this == obj)
             8                return true;
             9            return false;
            10        }

            11
            12        public static Boolean Equals(Object objA, Object objB)
            13        {
            14            //指向同一個對象,返回true
            15            if (objA == objB)
            16                return true;
            17
            18            //如果兩者任何一個為null,則不可能相等,返回false
            19            if ((objA == null||
            20                (objB == null))
            21                return false;
            22            
            23            //判斷objA和objB是否相等,返回比較結果
            24            return objA.Equals(objB);
            25        }

            26        
            27    }

            在這種實現中,個人認為Equals方法是沒有問題的,首先調用

             //首先讓基類比較其中的字段
                        if (!base.Equals(obj))
                            
            return false;

            比較了基類的部分,然后就比較自己的部分就OK了。
            再看書中的第二種,2)引用類型,從MyRefType到Object的繼承鏈上(基類、基類的基類、...),均沒有類覆蓋Object的Equals方法的實現;

             1//引用類型,從MyRefType到Object的繼承鏈上,均沒有類覆蓋Object的Equals方法
             2    class MyRefType : BaseType
             3    {
             4        RefType refobj;     //該字段是一個引用類型
             5        ValType valobj;     //該字段是一個值類型
             6
             7        public override bool Equals(object obj)
             8        {
             9            //因為this不是null,所以如果obj是null,那兩個對象將不可能相等
            10            if (obj == null)
            11                return false;
            12
            13            //如果類型不同,不可能相等
            14            if (this.GetType() != obj.GetType())
            15                return false;
            16            //將obj轉型為定義的類型以訪問其中的字段。
            17            //注意這里的轉型不會失敗,因為已經知道兩個對象是同一個類型
            18            //obj的運行時類型要么是MyRefType,要么是MyRefType的子類
            19            MyRefType other = (MyRefType)obj;
            20
            21            //比較其中的引用類型字段
            22            //這里調用Object的static 方法Equals,是為了兼容考慮refobj或者other.refobj為null的情況
            23            if (!Object.Equals(refobj, other.refobj))
            24                return false;
            25
            26            //比較其中的值類型字段,
            27            //因為值類型不可能為null,所以直接調用值類型的Equals方法,免得裝箱的開銷
            28            if (!valobj.Equals(other.valobj))
            29                return false;
            30
            31            return true;    //到這里兩個對象才算相等
            32        }

            33    }

            我們可以發現,同第一種實現的差別在于沒有了如下代碼段:

             //首先讓基類比較其中的字段
                        if (!base.Equals(obj))
                            
            return false;

            為什么不能加這一段呢?因為在這種實現環境下,我們設定了前提:從MyRefType到Object的繼承鏈上,均沒有類覆蓋Object的Equals方法。所以如果加了上面這段代碼,那實際調用的是Object類的實例方法Equals

            1public virtual Boolean Equals(Object obj)
            2        {
            3            //如果兩個引用指向同一個對象
            4            //它們肯定相等
            5            if (this == obj)
            6                return true;
            7            return false;
            8        }

            這樣,如果this和obj不指向同一個對象,則這個base.Equals(obj)肯定返回false,于是Equals也返回false,而在this和obj指向同一個對象,Equals返回true,這樣不就是Object的Equals()實現嗎?既然如此,何苦自己重新這個函數呢?既然重寫了,那肯定有不一樣的行為,于是下面的代碼段加入不得。

             //首先讓基類比較其中的字段
                        if (!base.Equals(obj))
                            
            return false;


            到這里,我們也可以理解。不過問題是,沒有加入這段代碼,從“(2)引用類型,從MyRefType到Object的繼承鏈上(基類、基類的基類、...),均沒有類覆蓋Object的Equals方法的實現”中,我們好像找不到比較基類成員的影子。不比較基類成員,是否合理呢?

            看下面例子,如果兩個Derived對象,無需比較Base部分的成員變量,那么下面的寫法是正確的,此時該程序打印出的結果為True。

             1using System;
             2using System.Collections.Generic;
             3using System.Text;
             4
             5namespace MyTest
             6{
             7    //定義一個引用類型
             8    class MyRefType
             9    {
            10        public MyRefType(int value)
            11        {
            12            this.value = value;
            13        }

            14
            15        private int value;
            16    }

            17    //定義一個值類型
            18    struct MyValueType
            19    {
            20        public MyValueType(int value)
            21        {
            22            this.value = value;
            23        }

            24
            25        private int value;
            26    }

            27
            28    //基類
            29    class Base
            30    {
            31        //基類的引用類型成員,為了代碼簡單,這里聲明為public
            32        public MyRefType baseRef;    
            33        //基類的值類型成員,為了代碼簡單,這里聲明為public
            34        public MyValueType baseValue;   
            35    }

            36    
            37    //子類
            38    class Derived:Base
            39    {
            40        //子類的引用類型成員,為了代碼簡單,這里聲明為public
            41        public MyRefType derivedRef; 
            42        //子類的引用類型成員,為了代碼簡單,這里聲明為public
            43        public MyValueType derivedValue;
            44
            45        //這里Base沒有覆蓋Object的Equals()方法,所以這里采用Equals()的第二種實現方式
            46        //(2)引用類型,從MyRefType到Object的繼承鏈上,均沒有類覆蓋Object的Equals方法
            47        public override Boolean Equals(Object obj)
            48        {
            49            if (obj == null)
            50                return false;
            51            if (this.GetType() != obj.GetType())
            52                return false;
            53            Derived other = (Derived)obj;
            54
            55            if (!Object.Equals(this.derivedRef, other.derivedRef))
            56                return false;
            57
            58            if (!derivedValue.Equals(other.derivedValue))
            59                return false;
            60          
            61            return true;
            62        }
                    
            63    }

            64         
            65
            66    class Program
            67    {
            68        static void Main(string[] args)
            69        {
            70            MyRefType refType1 = new MyRefType(1);
            71            MyRefType refType2 = new MyRefType(2);
            72            MyRefType refType3 = new MyRefType(3);
            73
            74            Derived d1 = new Derived();
            75            Derived d2 = new Derived();
            76
            77            d1.derivedRef = refType1;
            78            d1.baseRef = refType2;
            79
            80            d2.derivedRef = refType1;
            81            d2.baseRef = refType3;
            82
            83            System.Console.Write(d1.Equals(d2));
            84            System.Console.Read();            
            85        }

            86    }
                
            87}

            88

            但是有時邏輯要求,兩個Derived對象需要比較Base部分的成員變量,那上面的寫法就是錯誤的,此時應該修改為如下的代碼,該程序打印出的結果為False。

             1using System;
             2using System.Collections.Generic;
             3using System.Text;
             4
             5namespace MyTest
             6{
             7    //定義一個引用類型
             8    class MyRefType
             9    {
            10        public MyRefType(int value)
            11        {
            12            this.value = value;
            13        }

            14
            15        private int value;
            16    }

            17    //定義一個值類型
            18    struct MyValueType
            19    {
            20        public MyValueType(int value)
            21        {
            22            this.value = value;
            23        }

            24
            25        private int value;
            26    }

            27
            28    //基類
            29    class Base
            30    {
            31        //基類的引用類型成員,為了代碼簡單,這里聲明為public
            32        public MyRefType baseRef;    
            33        //基類的值類型成員,為了代碼簡單,這里聲明為public
            34        public MyValueType baseValue;   
            35    }

            36    
            37    //子類
            38    class Derived:Base
            39    {
            40        //子類的引用類型成員,為了代碼簡單,這里聲明為public
            41        public MyRefType derivedRef; 
            42        //子類的引用類型成員,為了代碼簡單,這里聲明為public
            43        public MyValueType derivedValue;
            44
            45        //這里Base沒有覆蓋Object的Equals()方法,所以這里采用Equals()的第二種實現方式
            46        //(2)引用類型,從MyRefType到Object的繼承鏈上,均沒有類覆蓋Object的Equals方法
            47        public override Boolean Equals(Object obj)
            48        {
            49            if (obj == null)
            50                return false;
            51            if (this.GetType() != obj.GetType())
            52                return false;
            53            Derived other = (Derived)obj;
            54
            55            if (!Object.Equals(this.derivedRef, other.derivedRef))
            56                return false;
            57
            58            if (!derivedValue.Equals(other.derivedValue))
            59                return false;
            60
            61            ///////////////////////////////////////////////////////////
            62            //這里要加入比較基類的成員部分,具體比較什么視實際需要而定
            63            if (!Object.Equals(this.baseRef, other.baseRef))
            64                return false;
            65
            66            if (!baseValue.Equals(other.baseValue))
            67                return false;
            68            //////////////////////////////////////////////////////////
            69
            70            return true;
            71        }
                    
            72    }

            73         
            74
            75    class Program
            76    {
            77        static void Main(string[] args)
            78        {
            79            MyRefType refType1 = new MyRefType(1);
            80            MyRefType refType2 = new MyRefType(2);
            81            MyRefType refType3 = new MyRefType(3);
            82
            83            Derived d1 = new Derived();
            84            Derived d2 = new Derived();
            85
            86            d1.derivedRef = refType1;
            87            d1.baseRef = refType2;
            88
            89            d2.derivedRef = refType1;
            90            d2.baseRef = refType3;
            91
            92            System.Console.Write(d1.Equals(d2));
            93            System.Console.Read();            
            94        }

            95    }
                
            96}

            97


            再看第三種實現:(3)值類型的Equals方法實現。書中代碼如下:

             1//值類型
             2    struct MyValType
             3    {
             4        RefType refobj;     //引用類型
             5        ValType valobj;     //值類型
             6
             7        public override bool Equals(object obj)
             8        {
             9            //這里不用GetType(),可以避免裝箱
            10            //同時,因為值類型不能有子類,所以這里用is就可以達到類型比較的目的
            11            if (!(obj is MyValType))
            12                return false;
            13            return this.Equals((MyValType)obj);
            14        }

            15
            16        public Boolean Equals(MyValType obj)
            17        {
            18            if (!Object.Equals(this.refobj, obj.refobj))
            19                return false;
            20            if (!this.valobj.Equals(obj.valobj))
            21                return false;
            22            return true;
            23        }

            24    }

            這種實現方法,如果不存在其它類對MyValType的隱式類型轉換,是沒有問題的,如果存在隱式類型轉換,那代碼中的強類型Equals()方法(從第16行開始)就可能存在問題了。試想想,兩種不同類型的實例,我們有多少場合會認為他們Equals呢?根據邏輯來定,一般不會認為它們相同。
            為了說明存在的這個問題,請看如下代碼:

             1 //值類型
             2    struct MyValType
             3    {
             4        private int value;     //值類型
             5
             6        public int Value
             7        {
             8            get return this.value; }
             9            set this.value = value; }
            10        }

            11
            12        public override bool Equals(object obj)
            13        {
            14            //這里不用GetType(),可以避免裝箱
            15            //同時,因為值類型不能有子類,所以這里用is就可以達到類型比較的目的
            16            if (!(obj is MyValType))
            17                return false;
            18            return this.Equals((MyValType)obj);
            19        }

            20
            21        public bool Equals(MyValType obj)
            22        {
            23            if (value != obj.Value)
            24                return false;
            25            return true;
            26        }

            27    }

            28
            29    //值類型
            30    struct MyValType2
            31    {
            32        private int value;     //值類型
            33
            34        public int Value
            35        {
            36            get return this.value; }
            37            set this.value = value; }
            38        }

            39
            40        public static implicit operator MyValType(MyValType2 obj)
            41        {
            42            MyValType myValType = new MyValType();
            43            myValType.Value = obj.Value;
            44            return myValType;
            45        }

            46    }

            47
            48    class Program
            49    {
            50        static void Main(string[] args)
            51        {
            52            MyValType myValue1 = new MyValType();
            53            myValue1.Value = 10;
            54
            55            MyValType2 myValue2 = new MyValType2();
            56            myValue2.Value = 10;
            57
            58            //這里會輸出True,從常理上說不應該,從程序邏輯上就是True
            59            //程序先將myValue2隱式轉換為MyValType
            60            //然后調用函數public bool Equals(MyValType obj);
            61            System.Console.WriteLine(myValue1.Equals(myValue2));
            62            System.Console.Read();
            63        }

            64    }

            上面代碼中,一般從常理來說,我們不會認為myValue1和myValue2相等,因為他們是不同類型的實例(myValue1屬于MyValType類型,myValue2屬于MyValType2類型)。但是實際輸出了結果True。個中原因在于定義了一個從MyValType2到MyValType的隱式轉換:

            1public static implicit operator MyValType(MyValType2 obj)
            2        {
            3            MyValType myValType = new MyValType();
            4            myValType.Value = obj.Value;
            5            return myValType;
            6        }

            于是在運行語句myValue1.Equals(myValue2)時,會先將myValue2轉換為一個MyValType類型的臨時變量,然后用MyValue1和這個臨時變量比較,此時調用強類型的比較函數,因為MyValType和MyValType2這兩個類型內部結構一樣,且兩變量的內部field的值相同,所以返回True。
            上面例子說明 ,如果不能確保沒有其他類型到該類型的隱式轉換,那萬無一失的辦法就是不實現強類型的Equals。調用默認的Equals方法或者實現參數為Object的Equals方法,雖然效率可能差一點,但是可靠。當然,如果可以確認沒有其他類型到該類型的隱式轉換,那實現強類型的Equals方法還是可以帶來效率的提升。(相同描述可參見《.net框架程序設計》)。

            關于Equals()方法的實現,基本上也就到此結束了。如果各位有什么好的心得,歡迎積極探討。

            posted on 2009-04-26 23:33 五味雜陳 閱讀(1524) 評論(0)  編輯 收藏 引用 所屬分類: .NET

            亚洲女久久久噜噜噜熟女| 三上悠亚久久精品| 色狠狠久久综合网| 日韩亚洲欧美久久久www综合网| 合区精品久久久中文字幕一区| 国产精品天天影视久久综合网| 色88久久久久高潮综合影院| 久久中文娱乐网| 国产色综合久久无码有码| 伊人久久大香线蕉无码麻豆| 久久精品国产欧美日韩| 国产精品伊人久久伊人电影| www.久久热.com| 18禁黄久久久AAA片| 国产69精品久久久久观看软件 | 欧美777精品久久久久网| 蜜桃麻豆www久久国产精品| 无码8090精品久久一区| 国产一区二区精品久久| 99久久人人爽亚洲精品美女| 久久99精品国产麻豆婷婷| 久久久这里有精品中文字幕| 99久久这里只有精品| 中文字幕无码免费久久| 欧美一级久久久久久久大片| 国产精品99久久久久久www| 精品少妇人妻av无码久久| 亚洲伊人久久大香线蕉苏妲己| 久久久国产精华液| AV色综合久久天堂AV色综合在| 偷窥少妇久久久久久久久| 久久伊人五月天论坛| 久久久久18| 久久强奷乱码老熟女网站| 国产成人99久久亚洲综合精品| 久久99国产精品久久99果冻传媒| 久久婷婷成人综合色综合| 久久久久99精品成人片欧美| 国产成人久久精品麻豆一区| 中文精品久久久久国产网址| 91精品国产91久久久久久|