2010-02-17 10 views
11

के साथ कस्टम प्रकार से समूह के लिए मैं इस वर्गकैसे LINQ

public class Item 
{ 
     public Coordinate coordinate { get; set; } 
     ... 
     ... 
} 

समन्वय के साथ इस तरह परिभाषित किया जा रहा है:

public class Coordinate 
{ 
     public Coordinate(float latitude, float longitude) 
     { 
      Latitude = latitude; 
      Longitude = longitude; 
     } 

     public float Latitude { get; private set; } 
     public float Longitude { get; private set; } 
} 

और मैं उस तरह एक LINQ क्वेरी करना चाहते हैं:

var grouped = from it in items 
       group it by it.Coordinate into grp 
       select grp; 

As mentioned here by MSDN मैंने सोचा कि यह संभव था अगर मैं अपने समन्वय वर्ग पर बराबर ओवरराइड कर दूं:

नामांकित प्रकार का उपयोग करें यदि आपको क्वेरी चर को दूसरी विधि में पास करना होगा। कुंजी के लिए स्वत: कार्यान्वित गुणों का उपयोग करके एक विशेष कक्षा बनाएं, और उसके बाद बराबर और GetHashCode विधियों को ओवरराइड करें। आप भी एक स्ट्रक्चर का उपयोग कर सकते हैं, जिस स्थिति में आप को विधियों को सख्ती से ओवरराइड करना नहीं चाहते हैं। अधिक जानकारी के लिए देखते हैं कैसे रहे हैं: लागू एक अपरिवर्तनीय कक्षा स्वत: लागू गुण

कार्यान्वयन के बराबर वर्ग समन्वय के लिए है कि:

public override bool Equals(object obj) 
{ 
     var coord = obj as Coordinate; 
     if(coord == null) return false; 
     return (Latitude == coord.Latitude && Longitude == coord.Longitude); 
} 

फिर भी मैं नहीं कर सकते इसी तरह निर्देशांक द्वारा समूह के लिए अपने LINQ क्वेरी मिल , के रूप में मेरे परीक्षण में विफल दिखाता है:

[TestMethod] 
public void GroupBy_3ItemsWith2DifferentCoordinates_Returns2Groups() 
{ 
    var items = new List<Item> 
     { 
      new Item {Coordinate = new Coordinate(10, 10)}, 
      new Item {Coordinate = new Coordinate(10, 10)}, 
      new Item {Coordinate = new Coordinate(12, 10)}, 
     }; 
    var grouped = from it in items 
        group it by it.Coordinate into g 
        select g; 
    Assert.AreEqual(2, grouped.Count()); 
} 

वहाँ के लिए एक अधिभार है GrouBy विधि जो IqualityComparer को पैरामीटर के रूप में लेती है, लेकिन क्या समूह खंड का उपयोग करने के बराबर है? क्या मैं कुछ गलत कर रहा हूं ?? कोई विचार?

उत्तर

22

आपने बराबर कार्यान्वयन दिखाया है, लेकिन GetHashCode नहीं। काम करने के लिए समूहबद्ध करने के लिए आपको दोनों (और लगातार तरीके से) ओवरराइड करना होगा।

नमूना GetHashCode कार्यान्वयन:

public override int GetHashCode() 
{ 
    int hash = 23; 
    hash = hash * 31 + Latitude.GetHashCode(); 
    hash = hash * 31 + Longitude.GetHashCode(); 
    return hash; 
} 

ध्यान दें कि सटीक समानता के लिए float मानों की तुलना हमेशा कुछ हद तक जोखिम भरा है - लेकिन मैं कम से कम यह देखते हुए कि वे किसी भी गणना प्रदर्शन नहीं कर रहे अपने इकाई परीक्षण पारित करने के लिए उम्मीद थी, ।

+0

बस इसे करने की कोशिश की, वो क्या है मैं याद आ रही थी।बढ़िया धन्यवाद :) सार्वजनिक ओवरराइड int GetHashCode() { वापसी ((int) अक्षांश * 100)^((int) रेखांश * 100); } –

+0

यदि आपका हैश कोड क्या कर रहा है, तो आपको यह सुनिश्चित करना चाहिए कि आपका समानता कोड इससे मेल खाता है - वे एक दूसरे के साथ संगत होना चाहिए। –

+0

अक्षांश। गेटहाशकोड()^रेखांश। गेटहाशकोड() अक्षांश और देशांतर को परिवर्तित करते समय समान परिणाम देता है। तो यह एक अच्छा समाधान नहीं था क्योंकि मैं यह सुनिश्चित करना चाहता हूं कि समन्वय (एक्स, वाई)! = समन्वय (वाई, एक्स); आपका कोड संचालन मामलों के आदेश के बाद से काम करता है। परिशुद्धता के लिए धन्यवाद, इससे मदद मिली :) –

2

GrouBy विधि है कि एक पैरामीटर के रूप में एक IEqualityComparer लेता है के लिए एक अधिभार नहीं है, लेकिन वहाँ समूह खंड का उपयोग कर बराबर है?

आप कर सकते हैं हमेशा एक गुमनाम प्रकार के आधार पर समूह, अगर आप बस एक त्वरित इनलाइन समाधान चाहते हैं और चाबी के लिए सही प्रकार से टकराने के बारे में चिंतित नहीं हैं:

var grouped = 
    from it in items 
    group it by new {it.Coordinate.Latitude, it.Coordinate.Longitude}; 
+0

मुझे वह समाधान पता था, लेकिन आपके पास समन्वय वर्ग कुंजी के रूप में नहीं होगा, केवल एक अनाम प्रकार। –