![](/img/trans.png)
[英]How to use IEqualityComparer<T>.Equals() in ToLookUp<T>() Extension
[英]How to use the IEqualityComparer
我的數據庫中有一些相同編號的鈴鐺。 我想在不重復的情況下獲得所有這些。 我創建了一個比較 class 來完成這項工作,但是 function 的執行導致 function 的很大延遲。從 0.6 秒到 2 秒!
我做得對還是必須使用其他方法?
reg.AddRange(
(from a in this.dataContext.reglements
join b in this.dataContext.Clients on a.Id_client equals b.Id
where a.date_v <= datefin && a.date_v >= datedeb
where a.Id_client == b.Id
orderby a.date_v descending
select new Class_reglement
{
nom = b.Nom,
code = b.code,
Numf = a.Numf,
})
.AsEnumerable()
.Distinct(new Compare())
.ToList());
class Compare : IEqualityComparer<Class_reglement>
{
public bool Equals(Class_reglement x, Class_reglement y)
{
if (x.Numf == y.Numf)
{
return true;
}
else { return false; }
}
public int GetHashCode(Class_reglement codeh)
{
return 0;
}
}
您的GetHashCode
實現始終返回相同的值。 Distinct
依賴於一個好的 hash function 來高效工作,因為它在內部構建了一個hash 表。
在實現類的接口時,閱讀文檔很重要,以了解您應該實現哪個合約。 1
在您的代碼中,解決方案是將GetHashCode
轉發到Class_reglement.Numf.GetHashCode
並在那里適當地實現它。
除此之外,您的Equals
方法充滿了不必要的代碼。 它可以重寫如下(相同的語義,1/4 的代碼,更具可讀性):
public bool Equals(Class_reglement x, Class_reglement y)
{
return x.Numf == y.Numf;
}
最后, ToList
調用是不必要且耗時的: AddRange
接受任何IEnumerable
,因此不需要轉換為List
。 AsEnumerable
在這里也是多余的,因為在AddRange
中處理結果無論如何都會導致這種情況。
1編寫代碼而不知道它實際做什么被稱為貨物崇拜編程。 這是一種令人驚訝的普遍做法。 它根本不起作用。
試試這段代碼:
public class GenericCompare<T> : IEqualityComparer<T> where T : class
{
private Func<T, object> _expr { get; set; }
public GenericCompare(Func<T, object> expr)
{
this._expr = expr;
}
public bool Equals(T x, T y)
{
var first = _expr.Invoke(x);
var sec = _expr.Invoke(y);
if (first != null && first.Equals(sec))
return true;
else
return false;
}
public int GetHashCode(T obj)
{
return obj.GetHashCode();
}
}
它的使用示例是
collection = collection
.Except(ExistedDataEles, new GenericCompare<DataEle>(x=>x.Id))
.ToList();
如果您想要一個基於 class 的屬性(充當鍵)為您的 class 創建 IEqualityComparer 的通用解決方案,請查看以下內容:
public class KeyBasedEqualityComparer<T, TKey> : IEqualityComparer<T>
{
private readonly Func<T, TKey> _keyGetter;
public KeyBasedEqualityComparer(Func<T, TKey> keyGetter)
{
if (default(T) == null)
{
_keyGetter = (x) => x == null ? default : keyGetter(x);
}
else
{
_keyGetter = keyGetter;
}
}
public bool Equals(T x, T y)
{
return EqualityComparer<TKey>.Default.Equals(_keyGetter(x), _keyGetter(y));
}
public int GetHashCode(T obj)
{
TKey key = _keyGetter(obj);
return key == null ? 0 : key.GetHashCode();
}
}
public static class KeyBasedEqualityComparer<T>
{
public static KeyBasedEqualityComparer<T, TKey> Create<TKey>(Func<T, TKey> keyGetter)
{
return new KeyBasedEqualityComparer<T, TKey>(keyGetter);
}
}
為了使用結構獲得更好的性能,沒有任何裝箱。
用法是這樣的:
IEqualityComparer<Class_reglement> equalityComparer =
KeyBasedEqualityComparer<Class_reglement>.Create(x => x.Numf);
只需編碼,實現GetHashCode
和NULL
驗證:
public class Class_reglementComparer : IEqualityComparer<Class_reglement>
{
public bool Equals(Class_reglement x, Class_reglement y)
{
if (x is null || y is null))
return false;
return x.Numf == y.Numf;
}
public int GetHashCode(Class_reglement product)
{
//Check whether the object is null
if (product is null) return 0;
//Get hash code for the Numf field if it is not null.
int hashNumf = product.hashNumf == null ? 0 : product.hashNumf.GetHashCode();
return hashNumf;
}
}
示例:由Numf區分的Class_reglement列表
List<Class_reglement> items = items.Distinct(new Class_reglementComparer());
包含您的比較 class (或更具體地說,您需要使用它來使其工作的AsEnumerable
調用)意味着排序邏輯從基於數據庫服務器變為位於數據庫客戶端(您的應用程序)上。 這意味着您的客戶端現在需要檢索並處理大量記錄,這總是比在可以使用適當索引的數據庫上執行查找效率低。
您應該嘗試開發一個滿足您的要求的 where 子句,有關更多詳細信息,請參閱使用帶有 LINQ 的 IEqualityComparer 到實體除外子句。
IEquatable<T>
可以是使用現代框架執行此操作的一種更簡單的方法。
你會得到一個簡單的bool Equals(T other)
function 並且不會亂用鑄造或創建單獨的 class。
public class Person : IEquatable<Person>
{
public Person(string name, string hometown)
{
this.Name = name;
this.Hometown = hometown;
}
public string Name { get; set; }
public string Hometown { get; set; }
// can't get much simpler than this!
public bool Equals(Person other)
{
return this.Name == other.Name && this.Hometown == other.Hometown;
}
public override int GetHashCode()
{
return Name.GetHashCode(); // see other links for hashcode guidance
}
}
請注意,如果在字典中使用它或使用類似Distinct
的東西,則必須實現GetHashCode
。
PS。 我不認為任何自定義 Equals 方法直接在數據庫端與實體框架一起使用(我認為您知道這一點是因為您使用 AsEnumerable),但這是一種更簡單的方法,可以在一般情況下執行簡單的 Equals。
如果事情似乎不起作用(例如在執行 ToDictionary 時出現重復鍵錯誤),請在 Equals 中放置一個斷點以確保它被命中並確保您已定義GetHashCode
(使用 override 關鍵字)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.