2013-08-21 9 views
5

Ich habe ein Objekt namens Page, mit einer Instanz namens p, die eine benutzerdefinierte Eigenschaft namens AssociatedAttributes hat. Wenn ich den folgenden Code:Kann mir jemand erklären, dass sich LINQs richtig mit mir schneiden? Ich verstehe nicht, warum das nicht funktioniert

int numMatchingAttributes = p.AssociatedAttributes.Intersect(p.AssociatedAttributes).Distinct().Count(); 

numMatchingAttributes landet gleich 0, obwohl p 6 AssociatedAttributes hat. Warum ist es nicht gleich 6?

AssociatedAttributes Typ ist List<Attribute> (Attribute meine eigene Klasse ist, nicht System.Attribute) und Attribute implementiert IComparable<Attribute>, ich habe es nicht implementieren IEquatable, soll ich?

Dies ist die Implementierung von CompareTo in Attribute:

public int CompareTo(Attribute other) 
{ 
    return Id.CompareTo(other.Id); 
} 

Id vom Typ Guid.

das ist die AssociatedAttributes Eigenschaft auf Seite:

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 ist ein OpenAccess- Kontext Telerik)

Update: Hier ist, was Arbeits endete: In Seite ist die folgende Methode:

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; 
      } 
     } 

Es ist hässlich, aber es funktioniert.

Antwort

8

Betrachten Sie die folgende Umsetzung 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" }, 
      }; 
     } 
    } 
} 

Hier die AssociatedAttributes Eigenschaft ist eine andere Liste Rückkehr jedes Mal AssociatedAttributes genannt wird. Darüber hinaus werden die tatsächlichen Elemente in der Liste jedes Mal erstellt, wenn die Eigenschaft aufgerufen wird, es werden nicht nur Referenzen auf die gleichen exakten Attribute Objekte zurückgegeben. Da Attribute (ich nehme an) überschreibt Equals oder GetHashCode nicht, wird es die Standard object Implementierung verwenden, die Objekte als gleich betrachtet, wenn und nur wenn sie das gleiche Objekt referenzieren. Da die Objekte in Ihren beiden Listen nicht auf dieselben Objekte verweisen, sind sie untereinander nicht gleich, obwohl sie intern möglicherweise dieselben Werte haben.

Die Tatsache, dass Attribute implementiert IComparable ist irrelivant.

Es gibt mehrere mögliche Dinge, die das Verhalten geschehen könnte sich ändern:

  1. Anstatt neue Objekte in der Eigenschaft Getter konstruieren, Rückverweise auf die gleichen aktuellen Objekte. Das würde wahrscheinlich bedeuten, ein privates Unterstützungsfeld für die Eigenschaft zu haben, die Objekte einmal zu konstruieren und dann Referenzen auf dieselbe Liste zurückzugeben.

  2. Überschreiben Sie Equals und GetHashCode in Attribute, um von seinen Werten und nicht von seiner Referenz abhängig zu sein. Konvention würde diktieren, dass Sie dies nur tun, wenn das Objekt unveränderlich ist, da der Umgang mit Objekten, die Werte GetHashCode mutieren, schwierig ist.Sie können IEquatablezusätzlich zu diesem Zweck implementieren, wenn Sie eine statisch typisierte Equals Methode bereitstellen möchten. Beachten Sie, dass es Vital ist, GetHashCode zu überschreiben, wenn Sie IEquatable implementieren, wenn Sie es immer noch nützlich sein möchten.

  3. Erstellen Sie ein neues Objekt, das IEqualityComparer<Attribute> implementiert. Dies wäre ein Objekt außerhalb von Attribute, das weiß, wie man sie auf der Grundlage einer anderen als der und GetHashCode Implementierung des Objekts selbst auf Gleichheit vergleicht. Stellen Sie eine Instanz eines solchen Typs für Intersect und Distinct bereit. (Sie haben jeweils Überladungen für benutzerdefinierte Gleichheitsvergleiche.)

+0

hmm, aber ich brauche tatsächliche Verweise auf bereits vorhandene Attributobjekte. Ich kann nicht nur neue generieren. Das mag nur für den Zweck der Zählung der Kreuzung funktionieren, würde aber für viel mehr nicht funktionieren, da es sich um neu konstruierte Objekte handelt. Ich habe nur den Schnitt der Seite gegen sich selbst als Test gemacht, um zu sehen, ob ich die Dinge richtig kodiere. – cray1

+0

@ user1911333 Ich sage nicht, dass Sie das tun sollten, ich sage, ich denke, Sie tun dies (oder etwas mit einem ähnlichen Effekt) bereits als Erklärung für Ihr beobachtetes Verhalten. Wenn Sie [meine Frage] (http://stackoverflow.com/questions/18365587/can-someone-explain-linqs-intersect-properly-to-me-i-dont-understand-why-this#comment26965710_18365587) darüber beantwortet haben, wie Die Eigenschaft ist implementiert, ich muss nicht raten. Ich sage nicht, dass dein Code * so aussehen sollte; In der Tat sollte es wahrscheinlich nicht. Wenn es so wäre, wäre es ziemlich ... ungewöhnlich. – Servy

+0

Nun, da Sie die Implementierung hinzugefügt haben, kann ich konkret sagen, dass Sie tatsächlich neue Objektinstanzen im Getter konstruieren, und das ist Ihr Problem. Die Optionen 1 oder 3 sind wahrscheinlich die beste Wahl für Sie. Ein ORM-Objekt ist wahrscheinlich veränderbar, und es würde auch im Allgemeinen nicht erwartet, dass es die Methoden "Equals" oder "GetHashCode" überschrieben hat. – Servy

Verwandte Themen