最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C#值類(lèi)型、引用類(lèi)型中的Equals和==的區(qū)別淺析

 更新時(shí)間:2015年01月05日 11:38:22   投稿:junjie  
這篇文章主要介紹了C#值類(lèi)型、引用類(lèi)型中的Equals和==的區(qū)別淺析,本文分別對(duì)C#值類(lèi)型和引用類(lèi)型中的Equals和==做了講解和給出了實(shí)例,需要的朋友可以參考下

引言

最近一個(gè)朋友正在找工作,他說(shuō)在筆試題中遇到Equals和==有什么區(qū)別的題,當(dāng)時(shí)跟他說(shuō)如果是值類(lèi)型的,它們沒(méi)有區(qū)別,如果是引用類(lèi)型的有區(qū)別,但string類(lèi)型除外。為了證實(shí)自己的說(shuō)法,也研究了一下,以免誤導(dǎo)別人,這里將研究結(jié)果總結(jié)一下,如果我有什么地方說(shuō)的不對(duì)的地方,望指出。

相等性

在定義類(lèi)或結(jié)構(gòu)時(shí),您將決定為類(lèi)型創(chuàng)建值相等性(或等效性)的自定義定義是否有意義。 通常,當(dāng)類(lèi)型的對(duì)象預(yù)期要添加到某類(lèi)集合時(shí),或者當(dāng)這些對(duì)象主要用于存儲(chǔ)一組字段或?qū)傩詴r(shí),您將實(shí)現(xiàn)值相等性。 您可以基于類(lèi)型中所有字段和屬性的比較來(lái)定義值相等性,也可以基于子集進(jìn)行定義。 但在任何一種情況下,類(lèi)和結(jié)構(gòu)中的實(shí)現(xiàn)均應(yīng)遵循五個(gè)等效性保證條件:

1.x.Equals(x) 返回 true. 。這稱(chēng)為自反屬性。
2.x.Equals(y) 返回與 Equals(x) 相同的值。 這稱(chēng)為對(duì)稱(chēng)屬性。
3.如果 (x.Equals(y) && y.Equals(z)) 返回 true,則 x.Equals(z) 返回 true。 這稱(chēng)為可傳遞屬性。
4.只要不修改 x 和 y 所引用的對(duì)象,x.Equals(y) 的后續(xù)調(diào)用就返回相同的值。
5.x.Equals(null) 返回 false。 但是,null.Equals(null) 會(huì)引發(fā)異常;它不遵循上面的第二條規(guī)則。

您定義的任何結(jié)構(gòu)已經(jīng)具有它從 Object.Equals(Object) 方法的 System.ValueType 重寫(xiě)中繼承的默認(rèn)值相等性實(shí)現(xiàn)。 此實(shí)現(xiàn)使用反射來(lái)檢查類(lèi)型中的所有公共和非公共字段以及屬性。 盡管此實(shí)現(xiàn)可生成正確的結(jié)果,但與您專(zhuān)門(mén)為類(lèi)型編寫(xiě)的自定義實(shí)現(xiàn)相比,它的速度相對(duì)較慢。

類(lèi)和結(jié)構(gòu)的值相等性的實(shí)現(xiàn)詳細(xì)信息不同。 但是,類(lèi)和結(jié)構(gòu)都需要相同的基礎(chǔ)步驟來(lái)實(shí)現(xiàn)相等性:

重寫(xiě) Object.Equals(Object)虛方法。 大多數(shù)情況下,您的 bool Equals( object obj ) 實(shí)現(xiàn)應(yīng)只調(diào)入作為 System.IEquatable<T> 接口的實(shí)現(xiàn)的類(lèi)型特定 Equals 方法。 (請(qǐng)參見(jiàn)步驟 2。)

通過(guò)提供類(lèi)型特定的 Equals 方法實(shí)現(xiàn) System.IEquatable<T> 接口。 實(shí)際的等效性比較將在此接口中執(zhí)行。 例如,您可能決定通過(guò)僅比較類(lèi)型中的一兩個(gè)字段來(lái)定義相等性。 不要從 Equals 中引發(fā)異常。 僅適用于類(lèi):此方法應(yīng)僅檢查類(lèi)中聲明的字段。 它應(yīng)調(diào)用 base.Equals 來(lái)檢查基類(lèi)中的字段。 (如果類(lèi)型直接從 Object 中繼承,則不要這樣做,因?yàn)?Object.Equals(Object) 的 Object 實(shí)現(xiàn)會(huì)執(zhí)行引用相等性檢查。)

可選,但建議這樣做:重載 == 和 != 運(yùn)算符。

重寫(xiě) Object.GetHashCode,使具有值相等性的兩個(gè)對(duì)象生成相同的哈希代碼。

可選:若要支持“大于”或“小于”定義,請(qǐng)為類(lèi)型實(shí)現(xiàn) IComparable<T> 接口,并同時(shí)重載 <= 和 >= 運(yùn)算符。

                         ——MSDN(http://msdn.microsoft.com/zh-cn/library/dd183755.aspx)這里將msdn的說(shuō)法貼在此處,方便查看。

值類(lèi)型

這里就以int類(lèi)型的為代表進(jìn)行分析,在分析之前先復(fù)習(xí)一下什么是重載?重載:簡(jiǎn)單的說(shuō)就是一個(gè)類(lèi)中的方法與另一個(gè)方法同名,但是參數(shù)列表個(gè)數(shù)或者類(lèi)型或者返回值類(lèi)型不同,則這兩個(gè)方法構(gòu)成重載。那么重載方法的調(diào)用規(guī)則是什么?那么先看下面的一段測(cè)試代碼:

復(fù)制代碼 代碼如下:

namespace Wolfy.EqualsDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            int a =1, b = 1;
            Console.WriteLine(Add(a,b));
            Console.Read();
        }
        static int Add(object a, object b)
        {
            Console.WriteLine("調(diào)用了object類(lèi)型參數(shù)列表的方法:");
            return (int)a + (int)b;
        }
        static int Add(int a, float b)
        {
            Console.WriteLine("調(diào)用了int,float類(lèi)型參數(shù)列表的方法:");
            return a + (int)b;
        }
        static int Add(int a, int b)
        {
            Console.WriteLine("調(diào)用了int類(lèi)型參數(shù)列表的方法:");
            return a + b;
        }
    }
}

測(cè)試結(jié)果:

說(shuō)明根據(jù)傳入實(shí)參的類(lèi)型,優(yōu)先匹配最相近的形參列表的方法。

那么我們將Add(int a ,int b)這個(gè)方法注釋掉,那么會(huì)調(diào)用哪個(gè)方法?

為什么花費(fèi)那么多口舌說(shuō)明上面的問(wèn)題,那么現(xiàn)在看一下Int32反編譯的代碼:

Int32有一個(gè)自己的Equals方法,有一個(gè)重寫(xiě)的Equals方法,如果兩個(gè)int類(lèi)型的值進(jìn)行比較,Equals和==是一樣的,因?yàn)樗鼉?yōu)先調(diào)用了下面的Equals方法,如果是下面的代碼,則會(huì)選擇重寫(xiě)的Equals方法。

復(fù)制代碼 代碼如下:

static void Main(string[] args)
        {
            int a = 1;
            object b = 1;
            Console.WriteLine(a.Equals(b));
            Console.Read();
        }

可見(jiàn),對(duì)于值類(lèi)型的Equals和==是一樣的。

引用類(lèi)型

在類(lèi)(引用類(lèi)型)上,兩種 Object.Equals(Object) 方法的默認(rèn)實(shí)現(xiàn)均執(zhí)行引用相等性比較,而不是值相等性檢查。 當(dāng)實(shí)施者重寫(xiě)虛方法時(shí),目的是為了為其指定值相等性語(yǔ)義。
即使類(lèi)不重載 == 和 != 運(yùn)算符,也可以將這些運(yùn)算符與類(lèi)一起使用。 但是,默認(rèn)行為是執(zhí)行引用相等性檢查。 在類(lèi)中,如果您重載 Equals 方法,則應(yīng)重載 == 和 != 運(yùn)算符,但這并不是必需的。

                                                                ——MSDN

測(cè)試代碼:

復(fù)制代碼 代碼如下:

static void Main(string[] args)
        {

            Person p1 = new Person() { Name = "wolfy" };
            Person p2 = new Person() { Name = "wolfy" };
            Person p3 = p2;
            bool r1 = p1 == p2;
            bool r2 = p1.Equals(p2);
            bool r3 = p2 == p3;
            bool r4 = p2.Equals(p3);
            bool r5 = object.ReferenceEquals(p1, p2);
            bool r6 = object.Equals(p1,p2);
            bool r7 = object.ReferenceEquals(p2, p3);
            Console.WriteLine("==\t"+r1);
            Console.WriteLine("Equals\t"+r2);
            Console.WriteLine("p3=p2\t"+r3);
            Console.WriteLine("p2.Equals(p3)\t"+r4);
            Console.WriteLine("object.ReferenceEquals\t" + r5);
            Console.WriteLine("object.Equals(p1,p2)\t" + r6);
            Console.WriteLine("object.ReferenceEquals(p2, p3)\t" + r7);
            Console.Read();
        }

結(jié)果:

順便反編譯一下Equals和ReferenceEquals方法,看看他們的實(shí)現(xiàn)如何?

復(fù)制代碼 代碼如下:

 // object
 [__DynamicallyInvokable, TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
 public static bool Equals(object objA, object objB)
 {
     return objA == objB || (objA != null && objB != null && objA.Equals(objB));
 }

// object
[__DynamicallyInvokable, ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success), TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
public static bool ReferenceEquals(object objA, object objB)
{
    return objA == objB;
}

通過(guò)上面的代碼,我們可以得出這樣的結(jié)論,引用類(lèi)型中Equals和ReferenceEquals的行為是相同的,==與ReferenceEquals的行為也相同,但string除外。

對(duì)特殊應(yīng)用類(lèi)型string的相等性,遵循值類(lèi)型的相等性。string類(lèi)型的反編譯后的Equals方法和==代碼如下:

復(fù)制代碼 代碼如下:

public override bool Equals(object obj)
        {
            if (this == null)
            {
                throw new NullReferenceException();
            }
            string text = obj as string;
            return text != null && (object.ReferenceEquals(this, obj) || (this.Length == text.Length && string.EqualsHelper(this, text)));
        }
        [__DynamicallyInvokable, ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail), TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
        public bool Equals(string value)
        {
            if (this == null)
            {
                throw new NullReferenceException();
            }
            return value != null && (object.ReferenceEquals(this, value) || (this.Length == value.Length && string.EqualsHelper(this, value)));
        }
        [__DynamicallyInvokable, SecuritySafeCritical]
        public bool Equals(string value, StringComparison comparisonType)
        {
            if (comparisonType < StringComparison.CurrentCulture || comparisonType > StringComparison.OrdinalIgnoreCase)
            {
                throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
            }
            if (this == value)
            {
                return true;
            }
            if (value == null)
            {
                return false;
            }
            switch (comparisonType)
            {
            case StringComparison.CurrentCulture:
                return CultureInfo.CurrentCulture.CompareInfo.Compare(this, value, CompareOptions.None) == 0;
            case StringComparison.CurrentCultureIgnoreCase:
                return CultureInfo.CurrentCulture.CompareInfo.Compare(this, value, CompareOptions.IgnoreCase) == 0;
            case StringComparison.InvariantCulture:
                return CultureInfo.InvariantCulture.CompareInfo.Compare(this, value, CompareOptions.None) == 0;
            case StringComparison.InvariantCultureIgnoreCase:
                return CultureInfo.InvariantCulture.CompareInfo.Compare(this, value, CompareOptions.IgnoreCase) == 0;
            case StringComparison.Ordinal:
                return this.Length == value.Length && string.EqualsHelper(this, value);
            case StringComparison.OrdinalIgnoreCase:
                if (this.Length != value.Length)
                {
                    return false;
                }
                if (this.IsAscii() && value.IsAscii())
                {
                    return string.CompareOrdinalIgnoreCaseHelper(this, value) == 0;
                }
                return TextInfo.CompareOrdinalIgnoreCase(this, value) == 0;
            default:
                throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
            }
        }
        [__DynamicallyInvokable, TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
        public static bool Equals(string a, string b)
        {
            return a == b || (a != null && b != null && a.Length == b.Length && string.EqualsHelper(a, b));
        }
        [__DynamicallyInvokable, SecuritySafeCritical]
        public static bool Equals(string a, string b, StringComparison comparisonType)
        {
            if (comparisonType < StringComparison.CurrentCulture || comparisonType > StringComparison.OrdinalIgnoreCase)
            {
                throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
            }
            if (a == b)
            {
                return true;
            }
            if (a == null || b == null)
            {
                return false;
            }
            switch (comparisonType)
            {
            case StringComparison.CurrentCulture:
                return CultureInfo.CurrentCulture.CompareInfo.Compare(a, b, CompareOptions.None) == 0;
            case StringComparison.CurrentCultureIgnoreCase:
                return CultureInfo.CurrentCulture.CompareInfo.Compare(a, b, CompareOptions.IgnoreCase) == 0;
            case StringComparison.InvariantCulture:
                return CultureInfo.InvariantCulture.CompareInfo.Compare(a, b, CompareOptions.None) == 0;
            case StringComparison.InvariantCultureIgnoreCase:
                return CultureInfo.InvariantCulture.CompareInfo.Compare(a, b, CompareOptions.IgnoreCase) == 0;
            case StringComparison.Ordinal:
                return a.Length == b.Length && string.EqualsHelper(a, b);
            case StringComparison.OrdinalIgnoreCase:
                if (a.Length != b.Length)
                {
                    return false;
                }
                if (a.IsAscii() && b.IsAscii())
                {
                    return string.CompareOrdinalIgnoreCaseHelper(a, b) == 0;
                }
                return TextInfo.CompareOrdinalIgnoreCase(a, b) == 0;
            default:
                throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
            }
        }
        [__DynamicallyInvokable, TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
        public static bool operator ==(string a, string b)
        {
            return string.Equals(a, b);
        }
        [__DynamicallyInvokable, TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
        public static bool operator !=(string a, string b)
        {
            return !string.Equals(a, b);
        }

從上面的代碼可以看出string類(lèi)型的Equals和==是一樣的。

復(fù)制代碼 代碼如下:

public static bool operator ==(string a, string b)
        {
            return string.Equals(a, b);
        }
[__DynamicallyInvokable, TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
        public static bool operator !=(string a, string b)
        {
            return !string.Equals(a, b);
        }

總結(jié)

值類(lèi)型具有它從 Object.Equals(Object) 方法的 System.ValueType 重寫(xiě)中繼承的默認(rèn)值相等性實(shí)現(xiàn)。特殊的引用類(lèi)型string類(lèi)型,因?yàn)橹貙?xiě)了Equals和==方法,所以string類(lèi)型的Equals和==與值類(lèi)型的相等性一樣。對(duì)于其他的引用類(lèi)型此時(shí)的Equals和==與引用相等ReferenceEquals的行為相同。

以上是由一個(gè)同事的問(wèn)題引起,中間也查了很多資料,發(fā)現(xiàn)這篇文章在草稿箱中躺了很久了,今天突然看到就拿出來(lái)曬曬。中間修修改改,總嘗試著用哪種方式來(lái)說(shuō)明這個(gè)老生常談的問(wèn)題更好些。以上有些觀點(diǎn),純屬個(gè)人見(jiàn)解,如果你有更好的理解方式,不妨分享一下。如果對(duì)你有所幫助,不妨點(diǎn)一下推薦,讓更多的人看到,說(shuō)說(shuō)自己對(duì)Equals和==的理解。

相關(guān)文章

  • C#隨機(jī)設(shè)置900-1100毫秒延遲的方法

    C#隨機(jī)設(shè)置900-1100毫秒延遲的方法

    這篇文章主要介紹了C#隨機(jī)設(shè)置900-1100毫秒延遲的方法,涉及C#中Thread.Sleep方法的使用技巧,需要的朋友可以參考下
    2015-04-04
  • C#基于Socket實(shí)現(xiàn)多人聊天功能

    C#基于Socket實(shí)現(xiàn)多人聊天功能

    這篇文章主要為大家詳細(xì)介紹了C#基于Socket實(shí)現(xiàn)多人聊天功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • c# Thread類(lèi)線程常用操作詳解

    c# Thread類(lèi)線程常用操作詳解

    這篇文章主要介紹了c# Thread類(lèi)線程常用操作詳解的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)使用c#,感興趣的朋友可以了解下
    2021-03-03
  • C#程序中使用LINQ to XML來(lái)查詢XML格式數(shù)據(jù)的實(shí)例

    C#程序中使用LINQ to XML來(lái)查詢XML格式數(shù)據(jù)的實(shí)例

    這篇文章主要介紹了C#程序中使用LINQ to XML來(lái)查詢XML格式數(shù)據(jù)的實(shí)例,LINQ to XML是.NET框架中集成的接口,可以將XML數(shù)據(jù)放到內(nèi)存中進(jìn)行處理,需要的朋友可以參考下
    2016-03-03
  • C#自定義字符串補(bǔ)0函數(shù)實(shí)例

    C#自定義字符串補(bǔ)0函數(shù)實(shí)例

    這篇文章主要介紹了C#自定義字符串補(bǔ)0函數(shù),通過(guò)一個(gè)自定義函數(shù)形式實(shí)例分析了C#操作字符串實(shí)現(xiàn)補(bǔ)零操作的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-03-03
  • 詳解WPF如何顯示具有層級(jí)關(guān)系的數(shù)據(jù)

    詳解WPF如何顯示具有層級(jí)關(guān)系的數(shù)據(jù)

    這篇文章主要為大家詳細(xì)介紹了在WPF中如何顯示具有層級(jí)關(guān)系的數(shù)據(jù),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-04-04
  • C#統(tǒng)計(jì)字符串的方法

    C#統(tǒng)計(jì)字符串的方法

    這篇文章主要為大家詳細(xì)介紹了C#統(tǒng)計(jì)字符串的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-03-03
  • 在GridControl控件上綁定圖片的幾種操作方式詳解

    在GridControl控件上綁定圖片的幾種操作方式詳解

    GridControl控件是經(jīng)常用來(lái)綁定數(shù)據(jù)的,一般以常規(guī)的字符內(nèi)容為主,有時(shí)候也會(huì)有圖片的顯示需要,這篇文章主要介紹了在GridControl控件上綁定圖片的幾種操作方式詳解,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-07-07
  • C#使用Json.Net進(jìn)行序列化和反序列化及定制化

    C#使用Json.Net進(jìn)行序列化和反序列化及定制化

    在本篇文章里小編給大家分享了關(guān)于C#使用Json.Net進(jìn)行序列化和反序列化及定制化的知識(shí)點(diǎn)總結(jié),需要的朋友們參考學(xué)習(xí)下。
    2019-05-05
  • C#實(shí)現(xiàn)集合自定義排序的三種方式

    C#實(shí)現(xiàn)集合自定義排序的三種方式

    在C#中,集合排序是一種常見(jiàn)的操作,它可以幫助我們對(duì)集合中的元素進(jìn)行排序,C#中提供了多種集合排序方法,包括Array.Sort、List.Sort、SortedList和SortedSet等,本文給大家介紹了C#實(shí)現(xiàn)集合自定義排序的三種方式,需要的朋友可以參考下
    2025-01-01

最新評(píng)論

恭城| 张家川| 分宜县| 万全县| 象山县| 凤台县| 新津县| 龙里县| 怀来县| 福安市| 青川县| 承德县| 建阳市| 西平县| 吴桥县| 门头沟区| 奈曼旗| 东乡县| 北流市| 抚顺县| 中西区| 福鼎市| 陇川县| 前郭尔| 高青县| 博罗县| 响水县| 三亚市| 宁阳县| 石城县| 宝应县| 桐梓县| 江陵县| 新巴尔虎右旗| 永寿县| 龙泉市| 乌审旗| 腾冲县| 秀山| 灯塔市| 凤冈县|