2009-01-11 17 views
51

के साथ IENumerable पर विशिष्ट # मैं यहाँ क्या करने की कोशिश कर रहा हूं। मैं LINQ से एक्सएमएल का उपयोग कर एक एक्सएमएल फ़ाइल से पूछताछ कर रहा हूं, जो मुझे एक आईनेमेरेबल <T> ऑब्जेक्ट देता है, जहां टी मेरा "ग्राम" वर्ग है, जो इस क्वेरी के परिणामों से भरा हुआ है। कुछ परिणाम दोहराया गया है तो मैं एक अलग तो की तरह, IEnumerable वस्तु पर() प्रदर्शन करने के लिए करना चाहते हैं: सी # कस्टम IEqualityComparer

public IEnumerable<Village> GetAllAlliances() 
{ 
    try 
    { 
     IEnumerable<Village> alliances = 
      from alliance in xmlDoc.Elements("Village") 
      where alliance.Element("AllianceName").Value != String.Empty 
      orderby alliance.Element("AllianceName").Value 
      select new Village 
      { 
       AllianceName = alliance.Element("AllianceName").Value 
      }; 

     // TODO: make it work... 
     return alliances.Distinct(new AllianceComparer()); 
    } 
    catch (Exception ex) 
    { 
     throw new Exception("GetAllAlliances", ex); 
    } 
} 

के रूप में डिफ़ॉल्ट comparer गांव वस्तु के लिए काम नहीं होता है, मैं एक कस्टम एक के रूप में देखा लागू किया, यहाँ AllianceComparer कक्षा में:

public class AllianceComparer : IEqualityComparer<Village> 
{ 
    #region IEqualityComparer<Village> Members 
    bool IEqualityComparer<Village>.Equals(Village x, Village y) 
    { 
     // Check whether the compared objects reference the same data. 
     if (Object.ReferenceEquals(x, y)) 
      return true; 

     // Check whether any of the compared objects is null. 
     if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null)) 
      return false; 

     return x.AllianceName == y.AllianceName; 
    } 

    int IEqualityComparer<Village>.GetHashCode(Village obj) 
    { 
     return obj.GetHashCode(); 
    } 
    #endregion 
} 

अलग() विधि काम नहीं करता है, जैसा कि मैंने साथ या इसके बिना परिणामों के बिल्कुल वैसा ही नंबर है। एक और बात, और मुझे नहीं पता कि यह आमतौर पर संभव है, लेकिन मैं यह देखने के लिए कि क्या समस्या हो सकती है, मैं AllianceComparer.Equals() में कदम नहीं उठा सकता।
मुझे इंटरनेट पर इसका उदाहरण मिला है, लेकिन मैं अपना कार्यान्वयन कार्य नहीं कर सकता।

उम्मीद है कि यहां कोई व्यक्ति यहां देख सकता है कि क्या गलत हो सकता है! अग्रिम धन्यवाद!

+0

आपका पकड़/फेंक निर्माण इसे बनाता है जहां कॉलिंग फ़ंक्शन अब पकड़ने (ArgumentException) या पकड़ (IOException) (उदाहरण) को चुनने का विकल्प नहीं चुन सकता है। इस मामले के लिए, आप संभवतः एक साथ प्रयास/पकड़ को हटाने से बेहतर हैं - इसके अलावा, विधि का नाम अपवाद स्टैकट्रेस संपत्ति का हिस्सा होगा। –

उत्तर

72

समस्या आपके GetHashCode के साथ है। आपको इसके बजाय AllianceName के हैश कोड को वापस करने के लिए इसे बदलना चाहिए।

int IEqualityComparer<Village>.GetHashCode(Village obj) 
{ 
    return obj.AllianceName.GetHashCode(); 
} 

बात, अगर Equals रिटर्न true, वस्तुओं एक ही हैश कोड है जो एक ही AllianceName के साथ विभिन्न Village वस्तुओं के लिए मामला नहीं है होना चाहिए। चूंकि Distinct आंतरिक रूप से हैश तालिका बनाकर काम करता है, तो आप समान ऑब्जेक्ट्स के साथ समाप्त हो जाएंगे जो विभिन्न हैश कोडों के कारण बिल्कुल मेल नहीं खाए जाएंगे।

इसी तरह, दो फाइलों की तुलना करने के लिए, यदि दो फाइलों का हैश समान नहीं है, तो आपको फ़ाइलों को स्वयं जांचने की आवश्यकता नहीं है। वे अलग होंगे। अन्यथा, आप यह देखना जारी रखेंगे कि वे वास्तव में समान हैं या नहीं। हैश तालिका है कि Distinct व्यवहार का उपयोग करता है।

+0

हम अलग के लिए विशिष्ट समानता विधियों को क्यों ओवरराइड नहीं कर सकते ?? – Boog

+0

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

6

या

return alliances.Select(v => v.AllianceName).Distinct(); 
+0

यह एक दिलचस्प वैकल्पिक दृष्टिकोण है जो प्रश्नकर्ता के प्रश्नकर्ता को IEqualityComparer का उपयोग कर कोड पर पुनर्विचार करने का कारण बनता है। यह मेरे लिए एक समस्या हल करता है, यही कारण है कि मुझे यह पसंद है। हालांकि, सवाल का जवाब नहीं है। मेरे मामले में, मैं कुंजी-मूल्य डेटा के संग्रह से अद्वितीय कुंजी निकालना चाहता था, और अनन्य कुंजी को सूची में अलग से स्टोर करना चाहता था। जैसा कि @superrcat ने उल्लेख किया है, लौटाए गए आईनेमेरेबल का सामान्य प्रकार इसे करके बदल दिया गया है। – Greg

10

return alliances.Select(v => v.AllianceName).Distinct();

कि IEnumerable<string>IEnumerable<Village> के बजाय वापस होगा करने के लिए लाइन

return alliances.Distinct(new AllianceComparer()); 

बदल जाते हैं।