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

C#中實(shí)現(xiàn)值相等(Value Equality)的詳細(xì)步驟

 更新時(shí)間:2026年01月12日 08:59:53   作者:無(wú)風(fēng)聽(tīng)海  
在 C# 中,相等并不是一個(gè)簡(jiǎn)單的問(wèn)題,很多開(kāi)發(fā)者認(rèn)為重寫(xiě) Equals 就夠了,但在真實(shí)系統(tǒng)中,錯(cuò)誤或不完整的相等實(shí)現(xiàn)會(huì)導(dǎo)致一些bug,本文將從底層機(jī)制出發(fā),給出標(biāo)準(zhǔn)、完整、可復(fù)用的值相等實(shí)現(xiàn)步驟,需要的朋友可以參考下

一、為什么“值相等”是一個(gè)需要認(rèn)真對(duì)待的問(wèn)題

在 C# 中,相等并不是一個(gè)簡(jiǎn)單的問(wèn)題
很多開(kāi)發(fā)者認(rèn)為重寫(xiě) Equals 就夠了,但在真實(shí)系統(tǒng)中,錯(cuò)誤或不完整的相等實(shí)現(xiàn)會(huì)導(dǎo)致:

  • Dictionary / HashSet 行為異常
  • 對(duì)象“看起來(lái)相等”,但集合中卻當(dāng)作不相等
  • ==、Equals、Contains 行為不一致
  • 隱蔽而難以排查的 Bug

這背后的原因在于:

.NET 的相等語(yǔ)義是一個(gè)由多個(gè)方法和接口共同構(gòu)成的協(xié)作體系,而不是單一方法。

本文將從底層機(jī)制出發(fā),給出標(biāo)準(zhǔn)、完整、可復(fù)用的實(shí)現(xiàn)步驟。

二、相等的兩種語(yǔ)義:引用相等 vs 值相等

在 .NET 中,存在兩種本質(zhì)不同的“相等”:

1. 引用相等(Reference Equality)

object.ReferenceEquals(a, b)
  • 判斷兩個(gè)變量是否指向同一對(duì)象實(shí)例
  • 類(reference type)的默認(rèn)行為

2. 值相等(Value Equality)

  • 判斷兩個(gè)對(duì)象的數(shù)據(jù)內(nèi)容是否相同
  • 由開(kāi)發(fā)者顯式定義和實(shí)現(xiàn)
var a = new Person("Tom", 18);
var b = new Person("Tom", 18);

ReferenceEquals(a, b); // false
a.Equals(b);           // true(如果實(shí)現(xiàn)了值相等)

三、.NET 相等體系的整體結(jié)構(gòu)

實(shí)現(xiàn)值相等,必須理解以下四個(gè)關(guān)鍵成員的職責(zé)分工:

成員角色
IEquatable<T>.Equals(T)類型安全、性能最優(yōu)的相等判斷
object.Equals(object)所有 .NET API 的統(tǒng)一入口
GetHashCode()哈希集合的基礎(chǔ)
== / != 運(yùn)算符語(yǔ)法層面的相等判斷(可選)

一個(gè)正確的值相等實(shí)現(xiàn),必須保證這些成員在語(yǔ)義上一致。

四、類(引用類型)實(shí)現(xiàn)值相等的標(biāo)準(zhǔn)步驟

以下步驟適用于絕大多數(shù)引用類型(class)。

Step 1:明確“相等”的語(yǔ)義(設(shè)計(jì)階段)

首先必須回答一個(gè)設(shè)計(jì)問(wèn)題:

哪些字段決定兩個(gè)對(duì)象在業(yè)務(wù)語(yǔ)義上是“相等”的?

例如:

Person 相等 ? Name 和 Age 都相等

這一步?jīng)]有代碼,但至關(guān)重要。

Step 2:實(shí)現(xiàn)IEquatable<T>.Equals(T other)(核心步驟)

public sealed class Person : IEquatable<Person>
{
    public string Name { get; }
    public int Age { get; }

    public bool Equals(Person other)
    {
        if (other is null) return false;
        return Name == other.Name && Age == other.Age;
    }
}

為什么這是核心?

  • 泛型集合(HashSet<T>、Dictionary<TKey, TValue>優(yōu)先調(diào)用它
  • 避免裝箱(boxing),性能優(yōu)于 object.Equals
  • 提供類型安全的比較語(yǔ)義

IEquatable<T> 是值相等的主入口。

Step 3:重寫(xiě)object.Equals(object obj)(必須)

public override bool Equals(object obj)
{
    return Equals(obj as Person);
}

為什么必須?

  • 大量 .NET API 只接受 object
  • object.Equals(a, b)、非泛型集合依賴它
  • 保證所有調(diào)用路徑的相等邏輯一致

規(guī)范要求

Equals(object) 必須委托給 Equals(T),而不是重復(fù)實(shí)現(xiàn)邏輯。

Step 4:重寫(xiě)GetHashCode()(必須)

public override int GetHashCode()
{
    return HashCode.Combine(Name, Age);
}

必須遵守的核心約束

如果 a.Equals(b) 為 true,
那么 a.GetHashCode() 必須等于 b.GetHashCode()。

否則:

  • HashSet<T> 會(huì)包含重復(fù)元素
  • Dictionary<TKey, TValue> 無(wú)法正確查找 key

實(shí)踐建議

  • 使用參與相等比較的字段
  • 避免使用可變字段
  • 不要依賴 string.GetHashCode() 的持久性

Step 5(可選但推薦):重載== / !=運(yùn)算符

public static bool operator ==(Person left, Person right)
{
    return object.Equals(left, right);
}

public static bool operator !=(Person left, Person right)
{
    return !object.Equals(left, right);
}

說(shuō)明

  • 默認(rèn)情況下,類的 == 比較的是引用
  • 重載后可使 == 與值相等語(yǔ)義一致
  • object.Equals 已處理所有 null 情況,是最安全的寫(xiě)法

五、完整標(biāo)準(zhǔn)實(shí)現(xiàn)模板

public sealed class Person : IEquatable<Person>
{
    public string Name { get; }
    public int Age { get; }

    public Person(string name, int age)
    {
        Name = name;
        Age = age;
    }

    public bool Equals(Person other)
    {
        if (other is null) return false;
        return Name == other.Name && Age == other.Age;
    }

    public override bool Equals(object obj)
        => Equals(obj as Person);

    public override int GetHashCode()
        => HashCode.Combine(Name, Age);

    public static bool operator ==(Person left, Person right)
        => object.Equals(left, right);

    public static bool operator !=(Person left, Person right)
        => !object.Equals(left, right);
}

六、結(jié)構(gòu)體(值類型)的補(bǔ)充說(shuō)明

  • struct 默認(rèn)按字段比較,但使用反射,性能較低
  • 推薦同樣實(shí)現(xiàn) IEquatable<T>
public struct Point : IEquatable<Point>
{
    public int X;
    public int Y;

    public bool Equals(Point other)
        => X == other.X && Y == other.Y;

    public override bool Equals(object obj)
        => obj is Point p && Equals(p);

    public override int GetHashCode()
        => HashCode.Combine(X, Y);
}

七、record:值相等的語(yǔ)言級(jí)支持(C# 9+)

public record Person(string Name, int Age);

編譯器自動(dòng)生成:

  • IEquatable<T>
  • Equals(object)
  • GetHashCode
  • == / !=
  • 不可變?cè)O(shè)計(jì)

對(duì)于值對(duì)象(Value Object),record 是首選方案。

八、常見(jiàn)錯(cuò)誤總結(jié)

  • 只實(shí)現(xiàn) IEquatable<T>,不重寫(xiě) Equals(object)
  • 重寫(xiě) Equals,但忘記 GetHashCode
  • ==Equals 語(yǔ)義不一致
  • GetHashCode 中使用可變字段
  • == 中直接調(diào)用 left.Equals(right)

九、結(jié)論

在 C# 中,實(shí)現(xiàn)值相等不是“重寫(xiě)一個(gè)方法”,
而是一個(gè)需要遵循明確步驟和約束的完整設(shè)計(jì)。

標(biāo)準(zhǔn)流程可以總結(jié)為:

  1. 明確定義相等語(yǔ)義
  2. 實(shí)現(xiàn) IEquatable<T>.Equals(T)
  3. 重寫(xiě) object.Equals(object)
  4. 重寫(xiě) GetHashCode()
  5. (可選)重載 == / !=

這套實(shí)現(xiàn),才能在語(yǔ)言層、集合層和框架層都保持一致、可靠的行為。

以上就是C#中實(shí)現(xiàn)值相等(Value Equality)的詳細(xì)步驟的詳細(xì)內(nèi)容,更多關(guān)于C#實(shí)現(xiàn)值相等Value Equality的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C#中函數(shù)的創(chuàng)建和閉包的理解

    C#中函數(shù)的創(chuàng)建和閉包的理解

    這篇文章主要介紹了C#中函數(shù)的創(chuàng)建和閉包的理解,本文講解了動(dòng)態(tài)創(chuàng)建函數(shù)、匿名函數(shù)不足之處、理解c#中的閉包、閉包的優(yōu)點(diǎn)等內(nèi)容,需要的朋友可以參考下
    2015-04-04
  • C#中Dynamic和Dictionary性能比較

    C#中Dynamic和Dictionary性能比較

    開(kāi)發(fā)中需要傳遞變參,考慮使用 dynamic 還是 Dictionary,dynamic 的編碼體驗(yàn)顯著優(yōu)于 Dictionary,如果性能差距不大的話,我會(huì)選擇使用dynamic。下面通過(guò)本文給大家詳細(xì)介紹下C#中Dynamic和Dictionary性能比較,一起看看吧
    2016-11-11
  • C#如何通過(guò)RFC連接sap系統(tǒng)

    C#如何通過(guò)RFC連接sap系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了C#如何通過(guò)RFC連接sap系統(tǒng)的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • 同步調(diào)用和異步調(diào)用WebService

    同步調(diào)用和異步調(diào)用WebService

    本文給大家介紹webservice同步調(diào)用和異步調(diào)用,同步調(diào)用就是一個(gè)同步操作會(huì)阻塞整個(gè)當(dāng)前的進(jìn)程,直到這個(gè)操作完成才能執(zhí)行下一段代碼,異步調(diào)用不會(huì)阻塞啟動(dòng)操作的調(diào)用線程,調(diào)用程序必須通過(guò)輪流檢測(cè),或者等待完成信號(hào)來(lái)發(fā)現(xiàn)調(diào)用的完成。小伙伴們跟著小編一起學(xué)習(xí)
    2015-09-09
  • C# 泛型字典 Dictionary的使用詳解

    C# 泛型字典 Dictionary的使用詳解

    本文主要介紹了C# 泛型字典 Dictionary的使用詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • C# Winform按鈕中圖片實(shí)現(xiàn)左圖右字的效果實(shí)例

    C# Winform按鈕中圖片實(shí)現(xiàn)左圖右字的效果實(shí)例

    這篇文章主要給大家介紹了關(guān)于C# Winform按鈕中圖片實(shí)現(xiàn)左圖右字效果的相關(guān)資料,文中通過(guò)圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • Unity打開(kāi)淘寶app并跳轉(zhuǎn)到商品頁(yè)面功能的實(shí)現(xiàn)方法

    Unity打開(kāi)淘寶app并跳轉(zhuǎn)到商品頁(yè)面功能的實(shí)現(xiàn)方法

    這篇文章主要給大家介紹了關(guān)于如何利用Unity打開(kāi)淘寶app并跳轉(zhuǎn)到商品頁(yè)面功能的相關(guān)資料,這個(gè)功能目前在網(wǎng)上找不到相關(guān)的解決方法,所以自己寫(xiě)了出來(lái),需要的朋友可以參考下
    2021-07-07
  • WinForm相對(duì)路徑的陷阱

    WinForm相對(duì)路徑的陷阱

    這篇文章主要介紹了WinForm相對(duì)路徑的陷阱,是在進(jìn)行C#程序設(shè)計(jì)中尤其需要注意的問(wèn)題,需要的朋友可以參考下
    2014-08-08
  • 理解C#生成驗(yàn)證碼的過(guò)程

    理解C#生成驗(yàn)證碼的過(guò)程

    這篇文章主要介紹了C#生成驗(yàn)證碼的過(guò)程,通過(guò)實(shí)例分析C#驗(yàn)證碼的生成原理,感興趣的小伙伴們可以參考一下
    2016-03-03
  • C#播放鈴聲最簡(jiǎn)單實(shí)現(xiàn)方法

    C#播放鈴聲最簡(jiǎn)單實(shí)現(xiàn)方法

    這篇文章主要介紹了C#播放鈴聲最簡(jiǎn)單實(shí)現(xiàn)方法,通過(guò)調(diào)用系統(tǒng)方法實(shí)現(xiàn)播放wav格式音頻文件的功能,是非常實(shí)用的技巧,需要的朋友可以參考下
    2014-12-12

最新評(píng)論

察雅县| 石棉县| 黑山县| 南宁市| 彭山县| 泉州市| 东城区| 恭城| 麻栗坡县| 建平县| 宝丰县| 徐州市| 韩城市| 基隆市| 东乌珠穆沁旗| 泰顺县| 鄂尔多斯市| 翼城县| 道真| 正蓝旗| 九寨沟县| 安达市| 长垣县| 洛宁县| 吕梁市| 丰原市| 云龙县| 高淳县| 右玉县| 喀什市| 年辖:市辖区| 连云港市| 建宁县| 吐鲁番市| 宝兴县| 盘锦市| 盐源县| 新宾| 南乐县| 云龙县| 铜鼓县|