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

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

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

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

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

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

這背后的原因在于:

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

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

二、相等的兩種語義:引用相等 vs 值相等

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

1. 引用相等(Reference Equality)

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

2. 值相等(Value Equality)

  • 判斷兩個對象的數(shù)據(jù)內(nè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)值相等,必須理解以下四個關(guān)鍵成員的職責(zé)分工:

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

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

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

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

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

首先必須回答一個設(shè)計問題:

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

例如:

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
  • 提供類型安全的比較語義

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

Step 3:重寫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:重寫GetHashCode()(必須)

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

必須遵守的核心約束

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

否則:

  • HashSet<T> 會包含重復(fù)元素
  • Dictionary<TKey, TValue> 無法正確查找 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);
}

說明

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

五、完整標(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ǔ)充說明

  • 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:值相等的語言級支持(C# 9+)

public record Person(string Name, int Age);

編譯器自動生成:

  • IEquatable<T>
  • Equals(object)
  • GetHashCode
  • == / !=
  • 不可變設(shè)計

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

八、常見錯誤總結(jié)

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

九、結(jié)論

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

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

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

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

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

相關(guān)文章

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

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

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

    C#中Dynamic和Dictionary性能比較

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

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

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

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

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

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

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

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

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

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

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

    WinForm相對路徑的陷阱

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

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

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

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

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

最新評論

邢台市| 阿鲁科尔沁旗| 如皋市| 德格县| 延津县| 万宁市| 宁河县| 浦县| 永川市| 崇信县| 大冶市| 武威市| 法库县| 绍兴市| 扬州市| 宝兴县| 乡城县| 泸水县| 大连市| 庆城县| 台江县| 新巴尔虎右旗| 开原市| 长治县| 延安市| 德江县| 灌阳县| 遂昌县| 醴陵市| 伊金霍洛旗| 肥东县| 乾安县| 阳江市| 偏关县| 巫溪县| 阿克陶县| 贵德县| 罗定市| 辽源市| 荥阳市| 镇康县|