[英]IEnumerable.Except() and a custom comparer
我在使用 Except() 方法時遇到問題。 它不返回差異,而是返回原始集。
我嘗試在帳戶 class 中實施 IEquatable 和 IEqualityComparer。我還嘗試為帳戶創建一個單獨的 IEqualityComparer class。
當從 main 調用 Except() 方法時,它似乎沒有調用我的自定義 Equals() 方法,但是當我嘗試 Count() 時,它確實調用了自定義 GetHashCode() 方法!
我確定我在某個地方犯了一個微不足道的錯誤,我希望一雙新鮮的眼睛能幫助我。
主要的:
IEnumerable<Account> everyPartnerID =
from partner in dataContext.Partners
select new Account { IDPartner = partner.ID, Name = partner.Name };
IEnumerable<Account> hasAccountPartnerID =
from partner in dataContext.Partners
from account in dataContext.Accounts
where
!partner.ID.Equals(Guid.Empty) &&
account.IDPartner.Equals(partner.ID) &&
account.Username.Equals("Special")
select new Account { IDPartner = partner.ID, Name = partner.Name };
IEnumerable<Account> noAccountPartnerID =
everyPartnerID.Except(
hasAccountPartnerID,
new LambdaComparer<Account>((x, y) => x.IDPartner.Equals(y.IDPartner)));
帳戶:
public class Account : IEquatable<Account>
{
public Guid IDPartner{ get; set; }
public string Name{ get; set; }
/* #region IEquatable<Account> Members
public bool Equals(Account other)
{
return this.IDPartner.Equals(other.IDPartner);
}
#endregion*/
}
拉姆達比較器:
public class LambdaComparer<T> : IEqualityComparer<T>
{
private readonly Func<T, T, bool> _lambdaComparer;
private readonly Func<T, int> _lambdaHash;
public LambdaComparer(Func<T, T, bool> lambdaComparer) :
this(lambdaComparer, o => o.GetHashCode())
{
}
public LambdaComparer(Func<T, T, bool> lambdaComparer, Func<T, int> lambdaHash)
{
if (lambdaComparer == null)
throw new ArgumentNullException("lambdaComparer");
if (lambdaHash == null)
throw new ArgumentNullException("lambdaHash");
_lambdaComparer = lambdaComparer;
_lambdaHash = lambdaHash;
}
public bool Equals(T x, T y)
{
return _lambdaComparer(x, y);
}
public int GetHashCode(T obj)
{
return _lambdaHash(obj);
}
}
基本上,當您只傳入一個函數時,您的LambdaComparer
類就會被破壞,因為如果您不提供其他任何東西,它就會使用“身份哈希代碼”提供程序。 散列碼由Except
,這就是導致問題的原因。
這里的三個選項:
實現您自己的ExceptBy
方法,然后最好將其貢獻給包含此類內容的MoreLINQ 。
使用IEqualityComparer<T>
的不同實現。 我有一個ProjectionEqualityComparer
類,您可以在MiscUtil 中使用 - 或者您可以使用在另一個問題中發布的代碼。
將 lambda 表達式傳遞到您的LambdaComparer
代碼中以用於哈希:
new LambdaComparer<Account>((x, y) => x.IDPartner.Equals(y.IDPartner)), x => x.IDPartner.GetHashCode());
您還可以快速修復您的 LambdaComparer 以在僅提供等式參數時工作,如下所示:
public LambdaComparer(Func<T, T, bool> lambdaComparer) :
this(lambdaComparer, o => 1)
{
}
看這里,如何使用和實現 IEqualityComparer 與 linq.Except 及其他方式。
https://www.dreamincode.net/forums/topic/352582-linq-by-example-3-methods-using-iequalitycomparer/
public class Department {
public string Code { get; set; }
public string Name { get; set; }
}
公共類部門比較器:IEqualityComparer {
// equal if their Codes are equal
public bool Equals(Department x, Department y) {
// reference the same objects?
if (Object.ReferenceEquals(x, y)) return true;
// is either null?
if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
return false;
return x.Code == y.Code;
}
public int GetHashCode(Department dept) {
// If Equals() returns true for a pair of objects
// then GetHashCode() must return the same value for these objects.
// if null default to 0
if (Object.ReferenceEquals(dept, null)) return 0;
return dept.Code.GetHashCode();
}
}
IEnumerable<Department> deptExcept = departments.Except(departments2,
new DepartmentComparer());
foreach (Department dept in deptExcept) {
Console.WriteLine("{0} {1}", dept.Code, dept.Name);
}
// departments not in departments2: AC, Accounts.
IMO,與此問題的其他解決方案相比,上面的答案是最簡單的解決方案。 我對其進行了調整,以便對 Object 類的 Equals() 和 GetHasCode() 使用相同的邏輯。 好處是這個解決方案對客戶端 linq 表達式是完全透明的。
public class Ericsson4GCell
{
public string CellName { get; set; }
public string OtherDependantProperty { get; set; }
public override bool Equals(Object y)
{
var rhsCell = y as Ericsson4GCell;
// reference the same objects?
if (Object.ReferenceEquals(this, rhsCell)) return true;
// is either null?
if (Object.ReferenceEquals(this, null) || Object.ReferenceEquals(rhsCell, null))
return false;
return this.CellName == rhsCell.CellName;
}
public override int GetHashCode()
{
// If Equals() returns true for a pair of objects
// then GetHashCode() must return the same value for these objects.
// if null default to 0
if (Object.ReferenceEquals(this, null)) return 0;
return this.CellName.GetHashCode();
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.