2022 鐵人賽文 搬回點部落
開始試煉
自訂class 如何算等於
首先 先來自訂class
class Employee
{
public int Id { get; set; }
public string Name { get; set; }
}
void Main()
{
var a = new Employee { Id = 1, Name = "a" };
var b = new Employee { Id = 1, Name = "a" };
a.Equals(b).Dump("a.Equals(b)");
(a == b).Dump("a == b");
var c = new List<Employee> { a, b };
var d = c.Distinct().Dump();
}
可以看到不管 怎樣的等於 跟 用LINQ Distinct
Employee class 都無法算等於
開始 VS2022 來幫忙吧
先點快速動作與重構
選產生Equals 與 GetHashCode…
程式碼就產好了
class Employee : IEquatable<Employee>
{
public int Id { get; set; }
public string Name { get; set; }
public override bool Equals(object obj)
{
return Equals(obj as Employee);
}
public bool Equals(Employee other)
{
return !(other is null) &&
Id == other.Id &&
Name == other.Name;
}
public override int GetHashCode()
{
int hashCode = -1919740922;
hashCode = hashCode * -1521134295 + Id.GetHashCode();
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(Name);
return hashCode;
}
public static bool operator ==(Employee left, Employee right)
{
return EqualityComparer<Employee>.Default.Equals(left, right);
}
public static bool operator !=(Employee left, Employee right)
{
return !(left == right);
}
}
整理重點
實做 IEquatable<T>
這樣就不用原生的public override bool Equals(object obj)
減少裝箱拆箱的問題
實做 operator 的 == 跟 !=
讓 自訂物件也可以用 Equals的邏輯做等於比對
GetHashCode 會用到的地方還挺多的 基本上就是算出這class唯一的數字
像是dictionary 當key時就會用到 GetHashCode 來比對
最後要比對都會是呼叫public bool Equals(Employee other)
然後就看比對邏輯就可以自己寫囉
延伸試煉
結束試煉
現在這些IDE都會幫忙產生了 真方便
C# Equality and Hashcodes
https://www.youtube.com/watch?v=QhpZxeAlX5w
https://github.com/JasperKent/Equality-And-Hashcodes
If You Implement Iequatable T You Still Must Override Object S Equals And Gethashcode
https://blog.paranoidcoding.com/2009/01/15/if-you-implement-iequatable-t-you-still-must-override-object-s-equals-and-gethashcode.html
void Main()
{
var a = new Employee { Id = 1, Name = "a" };
var b = new Employee { Id = 1, Name = "a" };
var c = new List<Employee> { a, b };
//var d = c.Distinct().Dump();
var d = c.Distinct(new EmployeeEqualityComparer()).Dump();
a.Equals(b).Dump();
(a == b).Dump();
}
class EmployeeEqualityComparer : IEqualityComparer<Employee>
{
public bool Equals(Employee x, Employee y)
{
return (x.Id == y.Id && x.Name == y.Name);
}
public int GetHashCode(Employee obj)
{
int hashCode = -1919740922;
hashCode = hashCode * -1521134295 + obj.Id.GetHashCode();
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(obj.Name);
return hashCode;
}
}
class Employee//: IEquatable<Employee>
{
public int Id { get; set; }
public string Name { get; set; }
//public bool Equals(Employee other)
//{
// if (ReferenceEquals(other, null))
// return false;
//
// return (Id == other.Id && Name == other.Name);
//}
// 可以不 override
// public override bool Equals(object obj)
// {
// Employee employee = (Employee)obj;
// return (Id == employee.Id && Name == employee.Name);
// }
//
//
//
//// 可以不 override
//public override int GetHashCode()
//{
// int hashCode = -1919740922;
// hashCode = hashCode * -1521134295 + Id.GetHashCode();
// hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(Name);
// return hashCode;
//}
//
// public int GetHashCode(Employee obj)
// {
// throw new NotImplementedException();
// }
//
// public static bool operator ==(Employee obj1, Employee obj2)
// {
// if (ReferenceEquals(obj1, obj2)) return true;
// if (ReferenceEquals(obj1, null)) return false;
// if (ReferenceEquals(obj2, null)) return false;
// return obj1.Equals(obj2);
// }
// public static bool operator !=(Employee obj1, Employee obj2) => !(obj1 == obj2);
}
如果內容有誤請多鞭策謝謝