我遇到了Except()方法的麻烦。 它不是返回差异,而是返回原始集合。
我已尝试在Account类中实现IEquatable和IEqualityComparer。 我也尝试为Account创建一个单独的IEqualityComparer类。
当从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*/
}
LambdaComparer:
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);
}
}
答案 0 :(得分:6)
基本上,当您传入一个函数时,您的LambdaComparer
类就会被破坏,因为如果您不提供任何其他功能,它将使用“身份哈希码”提供程序。哈希代码由Except
使用,这就是造成问题的原因。
这里有三个选项:
实施您自己的ExceptBy
方法,然后最好将其贡献给包含此类内容的MoreLINQ。
使用IEqualityComparer<T>
的其他实现。我有一个ProjectionEqualityComparer
课程,您可以在MiscUtil中使用 - 或者您可以使用代码as posted in another question。
将lambda表达式传递到您的LambdaComparer
代码中以用于哈希:
new LambdaComparer<Account>((x, y) => x.IDPartner.Equals(y.IDPartner)),
x => x.IDPartner.GetHashCode());
答案 1 :(得分:1)
当只提供如下所示的相等参数时,您还可以快速修复LambdaComparer:
public LambdaComparer(Func<T, T, bool> lambdaComparer) :
this(lambdaComparer, o => 1)
{
}
答案 2 :(得分:0)
请看这里,如何通过linq.Except及其他方式使用和实现IEqualityComparer。
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; }
}
公共类DepartmentComparer: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.