有人可以正确地解释LINQ的交叉吗?我不明白为什么这不起作用

时间:2013-08-21 19:02:12

标签: c# linq telerik-open-access

我有一个名为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;
            }
        }

这很难看,但确实有效。

1 个答案:

答案 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(我假设)不会覆盖EqualsGetHashCode,因此它将使用默认的object实现,当前和仅当它们引用相同的对象时宾语。由于两个列表中的对象没有引用相同的对象,因此它们都不相等,即使它们内部可能具有相同的值。

Attribute实现IComparable的事实是不可靠的。

可以采取一些措施来改变行为:

  1. 不是在属性getter中构造新对象,而是返回对相同实际对象的引用。这可能意味着为属性创建一个私有支持字段,构造对象一次,然后将引用返回到同一列表。

  2. 覆盖Equals中的GetHashCodeAttribute,以取决于其值,而不是其参考值。惯例将规定如果对象是不可变的,则只执行此操作,因为处理具有变异GetHashCode值的对象是困难的。如果需要,您可以另外实施IEquatable 来提供静态类型Equals方法。请注意,如果您实施GetHashCode,如果您仍希望它有用,那么至关重要会覆盖IEquatable

  3. 创建一个实现IEqualityComparer<Attribute>的新对象。这将是Attribute外部的一个对象,它知道如何根据对象本身的EqualsGetHashCode实现之外的其他内容来比较它们。向IntersectDistinct提供此类型的实例。 (它们每个都有自定义相等比较器的重载。)