青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

隨筆 - 13, 文章 - 0, 評論 - 3, 引用 - 0
數(shù)據(jù)加載中……

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

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

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

 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            //因?yàn)閠his不是null,所以如果obj是null,那兩個對象將不可能相等
14            if (obj == null)
15                return false;
16
17            //如果類型不同,不可能相等
18            if (this.GetType() != obj.GetType())
19                return false;
20            //將obj轉(zhuǎn)型為定義的類型以訪問其中的字段。
21            //注意這里的轉(zhuǎn)型不會失敗,因?yàn)橐呀?jīng)知道兩個對象是同一個類型
22            //obj的運(yùn)行時類型要么是MyRefType,要么是MyRefType的子類
23            MyRefType other = (MyRefType)obj;
24
25            //比較其中的引用類型字段
26            //這里調(diào)用Object的static 方法Equals,是為了兼容考慮refobj或者other.refobj為null的情況
27            if (!Object.Equals(refobj, other.refobj))
28                return false;
29
30            //比較其中的值類型字段,
31            //因?yàn)橹殿愋筒豢赡転閚ull,所以直接調(diào)用值類型的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是否相等,返回比較結(jié)果
24            return objA.Equals(objB);
25        }

26        
27    }

在這種實(shí)現(xiàn)中,個人認(rèn)為Equals方法是沒有問題的,首先調(diào)用

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

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

 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            //因?yàn)閠his不是null,所以如果obj是null,那兩個對象將不可能相等
10            if (obj == null)
11                return false;
12
13            //如果類型不同,不可能相等
14            if (this.GetType() != obj.GetType())
15                return false;
16            //將obj轉(zhuǎn)型為定義的類型以訪問其中的字段。
17            //注意這里的轉(zhuǎn)型不會失敗,因?yàn)橐呀?jīng)知道兩個對象是同一個類型
18            //obj的運(yùn)行時類型要么是MyRefType,要么是MyRefType的子類
19            MyRefType other = (MyRefType)obj;
20
21            //比較其中的引用類型字段
22            //這里調(diào)用Object的static 方法Equals,是為了兼容考慮refobj或者other.refobj為null的情況
23            if (!Object.Equals(refobj, other.refobj))
24                return false;
25
26            //比較其中的值類型字段,
27            //因?yàn)橹殿愋筒豢赡転閚ull,所以直接調(diào)用值類型的Equals方法,免得裝箱的開銷
28            if (!valobj.Equals(other.valobj))
29                return false;
30
31            return true;    //到這里兩個對象才算相等
32        }

33    }

我們可以發(fā)現(xiàn),同第一種實(shí)現(xiàn)的差別在于沒有了如下代碼段:

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

為什么不能加這一段呢?因?yàn)樵谶@種實(shí)現(xiàn)環(huán)境下,我們設(shè)定了前提:從MyRefType到Object的繼承鏈上,均沒有類覆蓋Object的Equals方法。所以如果加了上面這段代碼,那實(shí)際調(diào)用的是Object類的實(shí)例方法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()實(shí)現(xiàn)嗎?既然如此,何苦自己重新這個函數(shù)呢?既然重寫了,那肯定有不一樣的行為,于是下面的代碼段加入不得。

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


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

看下面例子,如果兩個Derived對象,無需比較Base部分的成員變量,那么下面的寫法是正確的,此時該程序打印出的結(jié)果為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()的第二種實(shí)現(xiàn)方式
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部分的成員變量,那上面的寫法就是錯誤的,此時應(yīng)該修改為如下的代碼,該程序打印出的結(jié)果為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()的第二種實(shí)現(xiàn)方式
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            //這里要加入比較基類的成員部分,具體比較什么視實(shí)際需要而定
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


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

 1//值類型
 2    struct MyValType
 3    {
 4        RefType refobj;     //引用類型
 5        ValType valobj;     //值類型
 6
 7        public override bool Equals(object obj)
 8        {
 9            //這里不用GetType(),可以避免裝箱
10            //同時,因?yàn)橹殿愋筒荒苡凶宇?,所以這里用is就可以達(dá)到類型比較的目的
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    }

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

 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            //同時,因?yàn)橹殿愋筒荒苡凶宇悾赃@里用is就可以達(dá)到類型比較的目的
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,從常理上說不應(yīng)該,從程序邏輯上就是True
59            //程序先將myValue2隱式轉(zhuǎn)換為MyValType
60            //然后調(diào)用函數(shù)public bool Equals(MyValType obj);
61            System.Console.WriteLine(myValue1.Equals(myValue2));
62            System.Console.Read();
63        }

64    }

上面代碼中,一般從常理來說,我們不會認(rèn)為myValue1和myValue2相等,因?yàn)樗麄兪遣煌愋偷膶?shí)例(myValue1屬于MyValType類型,myValue2屬于MyValType2類型)。但是實(shí)際輸出了結(jié)果True。個中原因在于定義了一個從MyValType2到MyValType的隱式轉(zhuǎn)換:

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

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

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

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

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            亚洲人成高清| 99日韩精品| 午夜精品区一区二区三| 日韩一二三在线视频播| 欧美四级剧情无删版影片| aa成人免费视频| 亚洲视频在线观看一区| 国产精品日韩一区二区| 欧美一区二区视频在线观看| 亚洲欧美日韩在线综合| 国产亚洲一区二区三区在线观看| 久久―日本道色综合久久| 久久久夜夜夜| 亚洲精品欧美日韩| 一本久道久久久| 国产日韩欧美中文| 欧美黄色免费网站| 欧美日韩国产在线播放| 久久精品国产欧美激情| 麻豆av一区二区三区| 亚洲淫性视频| 久久久亚洲一区| 亚洲视频一区二区| 久久久亚洲国产天美传媒修理工| 亚洲欧洲三级| 亚洲一区国产视频| 亚洲人成人一区二区三区| 亚洲免费网站| 亚洲人成人一区二区在线观看| 99国产精品| **欧美日韩vr在线| 亚洲一二三级电影| 亚洲国产一区视频| 亚洲永久免费精品| 日韩香蕉视频| 欧美在线视频免费观看| av不卡在线观看| 久久精品二区亚洲w码| 一区二区三欧美| 老司机亚洲精品| 久久av一区| 欧美精品国产一区二区| 久久免费黄色| 国产精品一区二区在线观看不卡| 免费观看一区| 欧美精品午夜| 欧美va天堂va视频va在线| 国产精品视频内| a91a精品视频在线观看| 亚洲经典视频在线观看| 欧美中文字幕精品| 欧美在线视频日韩| 国产精品美女www爽爽爽视频| 欧美激情中文不卡| 在线精品福利| 久久精品国产亚洲一区二区三区| 亚洲永久视频| 欧美午夜a级限制福利片| 欧美国产极速在线| 亚洲国产精品久久久| 久久久久久久精| 久久夜精品va视频免费观看| 国产精品一区在线观看你懂的| 日韩视频在线观看国产| 一本色道久久综合亚洲精品小说| 欧美成人精品| 亚洲国产精品一区二区第四页av | 另类欧美日韩国产在线| 国产精品成人va在线观看| 亚洲精品色婷婷福利天堂| 亚洲精品视频在线观看免费| 麻豆精品一区二区av白丝在线| 欧美福利在线| 亚洲国内精品在线| 欧美精品999| 亚洲精品一区二区三区樱花| 日韩一区二区福利| 欧美人与性动交a欧美精品| 日韩视频不卡| 香蕉免费一区二区三区在线观看 | 欧美日韩一区二区在线视频| 亚洲精品系列| 亚洲字幕一区二区| 国产专区一区| 欧美freesex8一10精品| 亚洲国内高清视频| 亚洲欧美日韩成人| 国内激情久久| 欧美成人午夜剧场免费观看| 亚洲日本欧美| 欧美一级视频免费在线观看| 韩国福利一区| 欧美顶级大胆免费视频| 在线中文字幕不卡| 久久亚洲欧美国产精品乐播| 亚洲精品一区在线| 国产精品久久国产精品99gif| 午夜精品www| 欧美国产精品va在线观看| 宅男在线国产精品| 国产亚洲日本欧美韩国| 欧美成人免费小视频| 亚洲午夜精品一区二区| 欧美1区2区3区| 亚洲自拍电影| 在线观看三级视频欧美| 欧美日韩一区二区在线视频 | 欧美一区二区三区视频在线| 免费日韩成人| 午夜精品国产| 亚洲第一视频网站| 国产美女精品| 欧美日韩国产在线| 久久久伊人欧美| 中日韩美女免费视频网址在线观看 | 久久黄金**| 亚洲毛片一区| 狠狠色综合网站久久久久久久| 欧美全黄视频| 久久综合色8888| 欧美在线观看视频| 亚洲深夜福利| 亚洲国产高清aⅴ视频| 久久精品国产一区二区三| 一本一本a久久| 亚洲第一综合天堂另类专| 国产精品电影网站| 欧美国产亚洲精品久久久8v| 久久精品视频免费| 先锋影音国产精品| 亚洲在线观看免费| 99国产一区| 99国产精品久久久久久久成人热| 鲁大师成人一区二区三区| 久久国产毛片| 欧美一级久久| 欧美一区二区三区四区高清| 中文一区在线| 亚洲一区二区三区四区视频| 日韩视频一区二区三区| 91久久线看在观草草青青| 亚洲国产精品久久久久秋霞蜜臀| 国产亚洲精品bt天堂精选| 国产午夜精品一区二区三区欧美| 国产伦精品一区二区三| 国产精品久久久久久av福利软件| 欧美日本亚洲视频| 欧美日韩蜜桃| 国产精品v欧美精品v日本精品动漫 | 午夜性色一区二区三区免费视频| 99国产精品| 亚洲一级黄色片| 午夜久久一区| 久久精品首页| 另类亚洲自拍| 欧美高清视频| 欧美色视频日本高清在线观看| 欧美日韩在线看| 国产精品露脸自拍| 国产亚洲激情在线| 在线欧美视频| 亚洲精品一区二区网址| 国产精品99久久99久久久二8| 亚洲天堂网站在线观看视频| 亚洲专区欧美专区| 久久久久久免费| 欧美高清你懂得| 亚洲精品视频在线播放| 亚洲五月婷婷| 久久理论片午夜琪琪电影网| 欧美成人自拍| 国产精品免费一区豆花| 国产一区二区三区精品久久久| 狠狠色丁香久久婷婷综合丁香 | 欧美日韩1区2区| 国产精品一区免费观看| 在线观看国产欧美| 亚洲午夜久久久久久久久电影院| 午夜精品在线看| 欧美va亚洲va香蕉在线| 日韩视频免费观看高清完整版| 午夜精品久久久久99热蜜桃导演| 久久亚洲国产精品日日av夜夜| 欧美日韩国产一区二区三区| 国产亚洲欧美一区二区三区| 一本久久青青| 久久在线免费观看视频| 99精品视频一区二区三区| 欧美与黑人午夜性猛交久久久| 欧美精品二区| 影音先锋在线一区| 亚洲欧美日韩精品在线| 欧美激情二区三区| 午夜电影亚洲| 欧美日韩伦理在线免费| 一区二区三区亚洲| 性欧美videos另类喷潮| 亚洲人成人一区二区在线观看| 午夜日本精品| 国产精品久久波多野结衣|