我有一个名为Page的对象,其中一个名为p的实例具有一个名为AssociatedAttributes的自定义属性。如果我执行以下操作:
int numMatchingAttributes = p.AssociatedAttributes.Intersect( p.AssociatedAttributes ).Distinct( ).Count( );
numMatchingAttributes最终等于0,即使p有6个AssociatedAttributes。为什么它不等于6?
AssociatedAttributes
属于List<Attribute>
类型(Attribute
是我自己的类,而不是System.Attribute
)而Attribute
实现了IComparable<Attribute>
,我没有我应该实施IEquatable
吗?
这是属性中的CompareTo
的实现:
public int CompareTo(Attribute other)
{
return Id.CompareTo(other.Id);
}
Id
的类型为Guid
。
这是Page:
上的AssociatedAttributes属性public List<Attribute> AssociatedAttributes
{
get
{
List<Attribute> list = new List<Attribute>( );
using (
PredictiveRecommendor dbContext =
new PredictiveRecommendor()){
if ( dbContext != null )
{
IQueryable<Attribute> query = from a in dbContext.PageAttributes
where a.Page.Id.Equals(this.Id)
select a.Attribute;
list = query.ToList();
}
}
return list;
}
}
(dbContext是Telerik OpenAccess上下文)
更新:以下是最终工作:在页面中是以下方法:
public int numberOfIntersectedAssociatedAttributes ( Page other )
{
using ( PredictiveRecommendor dbContext = new PredictiveRecommendor( ) )
{
IQueryable<Attribute> thisAssocAttributes = from a in dbContext.PageAttributes
where a.Page.Id.Equals( this.Id )
select a.Attribute;
IQueryable<Attribute> otherAssocAttributes = from a in dbContext.PageAttributes
where a.Page.Id.Equals( other.Id )
select a.Attribute;
IQueryable<Attribute> interSection = thisAssocAttributes.Intersect( otherAssocAttributes );
return interSection.ToList( ).Count;
}
}
这很难看,但确实有效。
答案 0 :(得分:8)
考虑Page
的以下实现:
public class Page
{
public List<Attribute> AssociatedAttributes
{
get
{
return new List<Attribute>() {
new Attribute { Value = "a" },
new Attribute { Value = "b" },
new Attribute { Value = "c" },
};
}
}
}
此处AssociatedAttributes
属性每次调用AssociatedAttributes
时都会返回不同的列表。此外,每次调用属性时都会构造列表中的实际项目,而不仅仅是返回对相同精确Attribute
对象的引用。由于Attribute
(我假设)不会覆盖Equals
或GetHashCode
,因此它将使用默认的object
实现,当前和仅当它们引用相同的对象时宾语。由于两个列表中的对象没有引用相同的对象,因此它们都不相等,即使它们内部可能具有相同的值。
Attribute
实现IComparable
的事实是不可靠的。
可以采取一些措施来改变行为:
不是在属性getter中构造新对象,而是返回对相同实际对象的引用。这可能意味着为属性创建一个私有支持字段,构造对象一次,然后将引用返回到同一列表。
覆盖Equals
中的GetHashCode
和Attribute
,以取决于其值,而不是其参考值。惯例将规定如果对象是不可变的,则只执行此操作,因为处理具有变异GetHashCode
值的对象是困难的。如果需要,您可以另外实施IEquatable
来提供静态类型Equals
方法。请注意,如果您实施GetHashCode
,如果您仍希望它有用,那么至关重要会覆盖IEquatable
。
创建一个实现IEqualityComparer<Attribute>
的新对象。这将是Attribute
外部的一个对象,它知道如何根据对象本身的Equals
和GetHashCode
实现之外的其他内容来比较它们。向Intersect
和Distinct
提供此类型的实例。 (它们每个都有自定义相等比较器的重载。)