2009-03-04 15 views
6

यदि मैं बराबर और GetHashCode ओवरराइड करता हूं, तो मैं कैसे तय करूं कि किन फ़ील्ड की तुलना करना है? और क्या होगा यदि मेरे पास दो फ़ील्ड वाले दो ऑब्जेक्ट हैं, लेकिन बराबर केवल एक फ़ील्ड की जांच करता है?बराबर ओवरराइड() लेकिन सभी क्षेत्रों की जांच नहीं - क्या होगा?

दूसरे शब्दों में, चलो कहते हैं कि मैं इस वर्ग डालते हैं:

class EqualsTestClass 
{ 
    public string MyDescription { get; set; } 
    public int MyId { get; set; } 

    public override bool Equals(object obj) 
    { 
     EqualsTestClass eq = obj as EqualsTestClass; 
     if(eq == null) { 
      return false; 
     } else { 
      return MyId.Equals(eq.MyId); 
     } 
    } 

    public override int GetHashCode() 
    { 
     int hashcode = 23; 
     return (hashcode * 17) + MyId.GetHashCode(); 
    } 
} 

मैं दो वस्तुओं बराबर पर विचार अगर वे एक ही MyID है। तो यदि आईडी बराबर है लेकिन विवरण अलग है, तो उन्हें अभी भी बराबर माना जाता है।

मैं सिर्फ आश्चर्य है कि क्या इस दृष्टिकोण का नुकसान कर रहे हैं? बेशक, इस तरह एक निर्माण के रूप में की उम्मीद कैसे कार्य करेगा:

 List<EqualsTestClass> test = new List<EqualsTestClass>(); 

     EqualsTestClass eq1 = new EqualsTestClass(); 
     eq1.MyId = 1; 
     eq1.MyDescription = "Des1"; 

     EqualsTestClass eq2 = new EqualsTestClass(); 
     eq2.MyId = 1; 
     eq2.MyDescription = "Des2"; 

     test.Add(eq1); 
     if (!test.Contains(eq2)) 
     { 
      // Will not be executed, as test.Contains is true 
      test.Add(eq2); 
     } 

eq2 के रूप में मूल्य-बराबर eq1 के लिए है, यह नहीं जोड़ा जाएगा। लेकिन वह कोड है जिसे मैं नियंत्रित करता हूं, लेकिन मुझे आश्चर्य है कि ढांचे में कोड है जो अप्रत्याशित समस्याओं का कारण बन सकता है?

तो, क्या मुझे हमेशा अपने बराबर() तुलना में सभी सार्वजनिक क्षेत्रों को जोड़ना चाहिए, या कुछ खराब फ्रेमवर्क-मोजो की वजह से अजीब आश्चर्य से बचने के लिए दिशानिर्देश क्या हैं जो पूरी तरह से अप्रत्याशित थे?

उत्तर

11

Equals() ओवरराइड करने के लिए कारण यह है कि आप परिभाषित करते हैं, इसका क्या मतलब दो उदाहरणों बराबर होने के लिए है। कुछ मामलों में इसका मतलब है कि सभी फ़ील्ड बराबर होना चाहिए, लेकिन इसे नहीं करना है। आप तय करें।

अधिक जानकारी के लिए documentation और इस post देखते हैं।

+0

सहमत हुए, ओ पी की तरह, मैं बराबर() सिर्फ जांच करने के लिए overidden है

Public Class EqualsTestComparer Implements IEqualityComparer(Of EqualsTestClass) Public Function Equals1(ByVal x As EqualsTestClass, ByVal y As EqualsTestClass) As Boolean Implements System.Collections.Generic.IEqualityComparer(Of EqualsTestClass).Equals If x.MyId = y.MyId and x.MyDescription = y.MyDescription Then Return True Else Return False End If End Function Public Function GetHashCode1(ByVal obj As EqualsTestClass) As Integer Implements System.Collections.Generic.IEqualityComparer(Of EqualsTestClass).GetHashCode Return obj.ToString.ToLower.GetHashCode End Function End Class 

तो अपनी दिनचर्या में आप बस कस्टम comparer का उपयोग: यह कुछ इस तरह (VB में) लगेगा एक प्राथमिक आईडी, और यह है कि, पूरी तरह से प्रोग्रामर कॉल करते हैं। –

1

मुझे नहीं लगता कि आपको इस उदाहरण में फ्रेमवर्क के बारे में चिंता करने की आवश्यकता है। यदि आप क्लास डिज़ाइनर के रूप में उस कक्षा के दो उदाहरणों को बराबर मानते हैं तो वे समान मायआईडी साझा करते हैं, तो आपको केवल अपने ओवरडिन बराबर() और GetHashCode() विधियों में MyId का परीक्षण करने की आवश्यकता है।

1

आप केवल क्षेत्रों है कि मैच के लिए, अगर है सब से मेल खाना चाहिए कि आईडी तो उस के साथ जाने के लिए आवश्यक हैं के लिए जाँच करने की जरूरत है।

1

एक प्रश्न: यदि मैं बराबर और GetHashCode ओवरराइड करता हूं, तो मैं कैसे तय करूं कि मैं किस फ़ील्ड की तुलना करता हूं?

यह इस बात पर निर्भर करता है कि आप क्या करने की कोशिश कर रहे हैं। यदि आप यह देखने की कोशिश कर रहे हैं कि वस्तुएं बिल्कुल वही हैं, तो आपको उन सभी की तुलना करनी चाहिए। यदि आपके पास कुछ 'कुंजी' है और आप केवल यह जानना चाहते हैं कि वे एक ही 'ऑब्जेक्ट' हैं, भले ही अन्य डेटा अलग हो, तो बस 'कुंजी' मानों की जांच करें।

और क्या होगा यदि मेरे पास दो फ़ील्ड के साथ दो वस्तुएं हों, लेकिन बराबर केवल एक फ़ील्ड की जांच करता है?

तब आपके पास एक समानता विधि होगी जो यह देखने के लिए जांचती है कि 'कुंजी' समान है या नहीं, और संभावित रूप से कई 'बराबर' ऑब्जेक्ट्स हो सकती हैं जिनमें आंतरिक भिन्नताएं हों।

1

दूसरों ने कहा है कि इस पूरी तरह से वैध है और उम्मीद है, और यह वास्तव में कैसे बराबरी संचालित करने के लिए माना जाता है है। तो कक्षा के रूप में इसके साथ कोई समस्या नहीं है।

मैं एक एपीआई के रूप में बहुत थोड़ा इस से सावधान रहना होगा। मुझे माफ़ कर दो अगर यह इरादा नहीं था: उस मामले में यह दूसरों को सावधानी बरतने का एक नोट है।

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

इस तरह के एक समझदार कारण का एक उदाहरण यह है कि एक फ़ील्ड एक "दृश्य कार्यान्वयन विस्तार" है, जैसे हैशटेबल-आधारित कंटेनर पर अधिकतम लोड फैक्टर। जोखिम भरा (हालांकि मोहक) कारण का एक उदाहरण है "क्योंकि मैंने बाद में विवरण जोड़ा और अगर कुछ तोड़ने के मामले में बराबर विधि को बदलना नहीं चाहता"।

तो यह थोड़ा सा अंतर्दृष्टि करने के लिए पूरी तरह से मान्य है, खासकर अगर आप स्पष्ट रूप से दस्तावेज करते हैं कि व्यवहार आश्चर्यजनक हो सकता है। इस तरह के बराबर तरीकों का समर्थन किया जाना चाहिए, क्योंकि उन पर प्रतिबंध लगाने से उन मामलों में पागल हो जाएगा जहां एक क्षेत्र स्पष्ट रूप से अप्रासंगिक है। लेकिन यह स्पष्ट होना चाहिए कि एक ही आईडी और अलग-अलग विवरणों के साथ दो आईडी-विवरण जोड़े बनाने का अर्थ क्यों है, लेकिन उन्हें दोनों को एक कंटेनर (जैसे हैशसेट) में जोड़ने का अर्थ नहीं है जो डुप्लिकेट को रोकने के लिए बराबर/हैशकोड का उपयोग करता है प्रविष्टियों।

0

आपका उदाहरण यह देखने के लिए जांच कर रहा है कि एक सूची (EqualsTestClass) में एक ही प्रकार के ऑब्जेक्ट को एक ही गुण मान के साथ एक वस्तु है। बराबर ओवरराइड किए बिना इस कार्य को पूरा करने का एक और तरीका (और बराबर की पारंपरिक समझ) एक कस्टम तुलनाकर्ता का उपयोग करना है।

If Not test.Contains(eq2, New EqualsTestComparer) Then 
    //Do Stuff 
End if 
संबंधित मुद्दे