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

cra*_*ay1 5 c# linq telerik-open-access

我有一个名为Page的对象,其中一个名为p的实例具有一个名为AssociatedAttributes的自定义属性.如果我执行以下操作:

int numMatchingAttributes = p.AssociatedAttributes.Intersect( p.AssociatedAttributes ).Distinct( ).Count( ); 
Run Code Online (Sandbox Code Playgroud)

numMatchingAttributes最终等于0,即使p有6个AssociatedAttributes.为什么它不等于6?

AssociatedAttributes是Type List<Attribute>(Attribute是我自己的类,不是System.Attribute)和Attribute实现IComparable<Attribute>,我没有它实现IEquatable,我应该吗?

这是CompareTo属性中的实现:

public int CompareTo(Attribute other)
{
    return Id.CompareTo(other.Id);
}
Run Code Online (Sandbox Code Playgroud)

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;
            }
        }
Run Code Online (Sandbox Code Playgroud)

(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;
            }
        }
Run Code Online (Sandbox Code Playgroud)

这很难看,但它确实有效.

Ser*_*rvy 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" }, 
            };
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

AssociatedAttributes每次AssociatedAttributes调用时,属性都返回一个不同的列表.此外,每次调用属性时都会构造列表中的实际项目,而不仅仅是返回对相同精确Attribute对象的引用.由于Attribute(我假设)不会覆盖EqualsGetHashCode,它将使用默认object实现,当前和仅当它们引用同一对象时,它会将对象视为相等.由于两个列表中的对象不引用相同的对象,因此它们中的任何一个都不相等,即使它们在内部可能具有相同的值.

Attribute工具IComparable是不重要的事实.

可以通过以下几种方式来改变行为:

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

  2. 倍率EqualsGetHashCodeAttribute依赖于它的值,而不是它的参考.惯例将规定如果对象是不可变的,你只会这样做,因为处理具有变异GetHashCode值的对象是困难的.IEquatable 除了这样做之外,如果需要,可以实现提供静态类型的Equals方法.请注意,这是至关重要的覆盖GetHashCode,如果你实现IEquatable,如果你还希望它是有用的.

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