[英]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.