2013-08-21 19 views
5

Mam obiekt o nazwie Strona, z instancją o nazwie p, która ma niestandardową właściwość o nazwie AssociatedAttributes. Jeśli wykonuję następujące czynności:Czy ktoś może wyjaśnić mi dokładnie krzyż LINQ? Nie rozumiem, dlaczego to nie zadziała

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

Funkcja numMatchingAttributes kończy się na wartości równej 0, mimo że p ma 6 Asocjacji Associated. Dlaczego nie jest równy 6?

AssociatedAttributes jest typu List<Attribute> (Attribute jest moje własne klasy, nie System.Attribute) i Attribute realizuje IComparable<Attribute>, nie mam go wdrożyć IEquatable, powinienem?

Jest to realizacja CompareTo w atrybucie:

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

Id jest typu Guid.

ten jest własnością AssociatedAttributes na stronie:

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 jest Telerik kontekst OpenAccess)

Aktualizacja: Oto, co skończyło się pracę: na stronie jest następująca metoda:

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

To brzydkie, ale działa.

Odpowiedz

8

Rozważmy następujący realizację 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" }, 
      }; 
     } 
    } 
} 

Tutaj własnością AssociatedAttributes wraca inną listę każdorazowo AssociatedAttributes jest tzw. Dodatkowo rzeczywiste elementy na liście są konstruowane za każdym razem, gdy wywoływana jest właściwość, to nie tylko zwracanie odwołań do tych samych obiektów Attribute. Ponieważ Attribute (zakładam) nie zastępuje Equals lub GetHashCode, użyje domyślnej implementacji object, która traktuje obiekty jako równe wtedy i tylko wtedy, gdy odwołują się do tego samego obiektu. Ponieważ obiekty na twoich listach nie odwołują się do tych samych obiektów, żadne z nich nie są sobie równe, mimo że mogą mieć te same wartości wewnętrznie.

Fakt, że Attribute implementuje IComparable jest nieistotny.

Istnieje kilka możliwych rzeczy, które można zrobić, aby zmienić zachowanie:

  1. Zamiast budowy nowych obiektów w getter własności, powrót odniesienia do tych samych rzeczywistych obiektów. To prawdopodobnie oznaczałoby posiadanie prywatnego pola wsparcia dla właściwości, konstruowanie obiektów raz, a następnie zwracanie odwołań do tej samej listy.

  2. Przesłonięcie Equals i GetHashCode w Attribute zależy od wartości, a nie od wartości. Konwencja dyktowałaby, że robisz to tylko wtedy, gdy obiekt jest niezmienny, ponieważ radzenie sobie z obiektami, które mutują wartości GetHashCode jest ... trudne.Oprócz tego można zaimplementować IEquatable , aby wykonać to, jeśli chcesz, dostarczyć statycznie wpisaną metodę: Equals. Zauważ, że jest vital, aby zastąpić GetHashCode, jeśli zaimplementujesz IEquatable, jeśli nadal chcesz, aby było użyteczne.

  3. Utwórz nowy obiekt, który implementuje IEqualityComparer<Attribute>. Byłby to obiekt zewnętrzny względem Attribute, który wie, jak porównać je dla równości w oparciu o coś innego niż implementacja samego obiektu. Podaj instancję tego typu do Intersect i Distinct. (Każda z nich ma przeciążenia dla niestandardowych porównywarek równości.)

+0

hmm, ale potrzebuję faktycznych odniesień do już istniejących obiektów atrybutów. Nie mogę po prostu wygenerować nowych. To może zadziałać tylko po to, by uzyskać liczbę punktów przecięcia, ale nie byłoby zbyt wiele, gdyby były nowo zbudowanymi obiektami. Zrobiłem tylko przecięcie strony z samym sobą, aby sprawdzić, czy poprawnie koduję. – cray1

+0

@ user1911333 Nie mówię, że powinieneś to zrobić, mówię, że myślę, że już to robisz (lub coś podobnego) jako wyjaśnienie twojego obserwowanego zachowania. Jeśli odpowiedziałeś [moje pytanie] (http://stackoverflow.com/questions/18365587/can-someone-explain-linqs-intersect-properly-to-me-i-dont-understand-white-this#comment26965710_18365587) o tym, jak właściwość jest zaimplementowana, może nie muszę zgadywać. Nie mówię, że twój kod * powinien * wyglądać tak; w rzeczywistości prawdopodobnie nie powinien. Gdyby tak było, byłoby to całkiem ... niezwykłe. – Servy

+0

Po dodaniu implementacji mogę konkretnie powiedzieć, że faktycznie konstruujesz nowe instancje obiektów w geterze i to jest twój problem. Opcje 1 lub 3 są prawdopodobnie najlepszym wyborem dla ciebie. Obiekt ORM jest prawdopodobnie zmienny, a także, ogólnie rzecz biorąc, nie powinno się przesłonić metod 'Equals' lub' GetHashCode'. – Servy

Powiązane problemy