對於普通的string、及其餘基礎類型並不須要實現,可是當你本身的引用類型實體須要進行比較就須要實現,特別是比較複雜的判等公示c#
須要實現bool Equals(CNMemo x, CNMemo y)
和int GetHashCode(CNMemo obj)
方法,並繼承IEqualityComparer
resharper插件能夠默認用alt-insert快捷鍵插入實現code
我這裏有四個屬性要比較繼承
MemoId:string接口
Title:stringstring
Tags:List
private sealed class CnMemoEqualityComparer : IEqualityComparer<CNMemo> { public bool Equals(CNMemo x, CNMemo y) { if (ReferenceEquals(x, y)) return true; if (ReferenceEquals(x, null)) return false; if (ReferenceEquals(y, null)) return false; if (x.GetType() != y.GetType()) return false; return string.Equals(x.MemoId, y.MemoId) && string.Equals(x.Content, y.Content) && string.Equals(x.Title, y.Title) && ((x.Tags == null && y.Tags == x.Tags) || (x.Tags != null && y.Tags != null && x.Tags.Count == y.Tags.Count && !x.Tags.Except(y.Tags).Any())); } public int GetHashCode(CNMemo obj) { return obj.ToString().GetHashCode(); } } public static IEqualityComparer<CNMemo> CnMemoComparer { get; } = new CnMemoEqualityComparer();
注意: 這裏的方法中會先執行GetHashCode方法,若是GetHashCode方法返回的是不相同的值,那就直接忽略Equals方法,因此我在GetHashCode中沒有使用resharper的默認實現it
public int GetHashCode(CNMemo obj) { unchecked { var hashCode = (obj.MemoId != null ? obj.MemoId.GetHashCode() : 0); hashCode = (hashCode * 397) ^ (obj.Content != null ? obj.Content.GetHashCode() : 0); hashCode = (hashCode * 397) ^ (obj.Title != null ? obj.Title.GetHashCode() : 0); hashCode = (hashCode * 397) ^ (obj.Tags != null ? obj.Tags.GetHashCode() : 0); return hashCode; } }
由於這樣Tags引用地址不同會致使GetHashCode不一致,obj.ToString().GetHashCode()
若是tostring方法返回內容相同,那麼就會使用bool Equals(CNMemo x, CNMemo y)
進行比較io
若是以前實現了 IEquatable<CNMemo>
也可以使用x.Equals(y)
來完成比較,這樣比較代碼就不用拷貝兩份了。
使用的時候就這樣new List<CNMemo>() { memo1 }.Except(new List<CNMemo>() { memo2 }, CNMemo.CnMemoComparer)
若是實現了 IEquatable<CNMemo>
而且注意GetHashCode方法的實現注意上面的問題,也可直接使用new List<CNMemo>() { memo1 }.Except(new List<CNMemo>() { memo2 })
可是默認GetHashCode這樣實現有什麼負面效果待後續考證,目前沒有發現反作用