前言
在現實中的編程生活里,我們時常遇到一個棘手的問題:如何比較兩個相同類型的對象是否 "相等",比如在 ERP 系統中,企業的信息非常重要,每一次更新維護,都需要系統自動地詳細記錄更新前后企業不一致的信息、更新時間和更新人等等。
但是,直接比較通常只能告訴我們它們是否指向同一個內存地址,而不能告訴我們它們的內容是否一致,所以即使兩個相同類型的對象的值都一致,程序還是偏偏說:"對不起,他們沒關系!" 那我們應該怎么辦呢?別急,接下來我們一起探索。
在 C# 中,要比較兩個對象實例是否相等,有一些常用的方法。
比如實現 IEquatable<T>
接口、重寫 Object.Equals
方法,或使用自定義比較邏輯等等。
以下是 7 種常用的方法:
1. 實現 IEquatable接口
實現 IEquatable<T>
接口是一個好習慣,就像在你的小屋里掛上一個 "歡迎光臨" 的牌子,讓外界知道你準備好接受比較了,實現這個接口之后,你還可以創建更強類型的比較方法。
public class Test : IEquatable<Test>
{
public int Id { get; set; }
public string Name { get; set; }
public bool Equals(Test other)
{
if (other == null)
return false;
return this.Id == other.Id && this.Name == other.Name;
}
public override bool Equals(object obj)
{
return Equals(obj as Test);
}
public override int GetHashCode()
{
return (Id, Name).GetHashCode(); // 可以使用 C# 7.3 中的元組
}
}
2. 重寫 Object.Equals 和 GetHashCode 方法
這是老派的做法,但依然有效。
當你重寫了 Equals
和 GetHashCode
方法后,你就能告訴對象們: "嘿,你們倆是一樣的!" 。
如果你使用的是 .NET8 或更高版本時,你還可以使用 源生成器 (source generators)
特性幫助自動生成 Equals
, GetHashCode
等常用方法,編程工作更輕松!
public class Test
{
public int Id { get; set; }
public string Name { get; set; }
public override bool Equals(object obj)
{
if (obj is Test other)
{
return this.Id == other.Id && this.Name == other.Name;
}
return false;
}
public override int GetHashCode()
{
return (Id, Name).GetHashCode();
}
}
3. 重載 == 操作符
有時候,我們更傾向于使用 ==
操作符來比較對象,為了讓你的代碼看起來更加自然,不妨重載一下這個操作符吧!
注意,重載 ==
操作符時,通常也要重載 !=
操作符
public class Test
{
public int Id { get; set; }
public string Name { get; set; }
public static bool operator ==(Test left, Test right)
{
if (left is null && right is null) return true;
if (left is null || right is null) return false;
return left.Equals(right);
}
public static bool operator !=(Test left, Test right)
{
return !(left == right);
}
public override bool Equals(object obj)
{
return obj is Test other && Equals(other);
}
public override int GetHashCode()
{
return (Id, Name).GetHashCode();
}
}
4. 利用匿名函數或 Lambda 表達式
如果你只是偶爾需要比較兩個對象,Lambda 表達式是個不錯的選擇,簡單又直接,快速搞定一切:
Test A = new Test { Id = 1, Name = "Test" };
Test B = new Test { Id = 1, Name = "Test" };
bool areEqual = A.Id == B.Id && A.Name == B.Name; // 手動比較屬性
5. 序列化為 Json 字符串再比較
如果你需要快速比較兩個復雜對象,可以考慮把它們序列化成 JSON 字符串然后進行比較,這種方法雖然不是直接的對象比較方法,但簡單粗暴,在某些情況下能大顯身手。
序列化推薦使用 System.Text.Json
(.NET 6 及之后的版本)或 Newtonsoft.Json
(第三方庫)這兩個庫。
using System.Text.Json;
var jsonA = JsonSerializer.Serialize(A);
var jsonB = JsonSerializer.Serialize(B);
bool areEqual = jsonA == jsonB; // 比較 JSON 字符串
需要注意的是,這種方法對于復雜類型或含有大量嵌套對象的情況,性能和效率可能比較差。
6. 直接比較
雖然說大多數情況,兩個相同類型的對象之間不能直接比較,但 record
類型是個例外。
如果你使用的是 .NET 6 及之后的版本,并且對象的類型是 record
類型,那么恭喜你!
因為記錄類型默認實現了 Equals
和 GetHashCode
方法,并且提供了 ==
和 !=
運算符重載,使得比較變得非常簡單
public record Test(int Id,string Name);
// 創建兩個 Test 對象
Test a = new Test(1, "test");
Test b = new Test(1, "test");
// 比較兩個對象是否相等
bool areEqual = a == b; // 返回 true
7. 使用第三方庫
最后,當然不能錯過各種強大的第三方庫,它們就像是你編程生活中的 "金牌助手" ,如果你懶得自己動手造輪子,它們會是你的最佳選擇,推薦幾個我常用的庫:
EqualityComparer,一個泛型類,可以用于比較兩個對象的相等性,例如:
bool areEqual = EqualityComparer<Test>.Default.Equals(A, B);
Objects Comparer,它允許逐個成員遞歸地比較對象,并為某些屬性、字段或類型定義自定義比較邏輯,例如:
var comparer = new ObjectsComparer<Test>;
var test1 = new Test(1, "test");
var test2 = new Test(1, "test");
var isEqual = comparer.Compare(test1, test2); // 比較兩個對象
......
Compare.NET Objects,可以更詳細地獲取兩個對象之間的差異,并記錄具體的差別,例如:
var test1 = new Test(1, "test");
var test2 = new Test(1, "test");
var propertyCount = 2;
CompareLogic compareLogic = new CompareLogic()
{
Config = new ComparisonConfig()
{
MaxDifferences = propertyCount //MaxDifferences的默認值是1
}
};
bool result = compareLogic.Compare(test1, test2).AreEqual;
Console.Write(result);
以上只是一些簡單的例子,小伙伴們可以到這些第三方庫的官網解鎖更多使用姿勢!
總結
比較對象是編程中的一項基本技能,它幫助我們維護數據的和諧,提升業務邏輯的效率,確保應用程序的正常運行,希望這 7 個方法能夠讓你在面對比較對象的任務時游刃有余!
記得在比較之前處理好 null
的情況,以免出現空引用異常哦!
該文章在 2024/12/13 9:26:22 編輯過