2010-03-02 14 views
32

मैं एक डोमेन मॉडल के साथ काम कर रहा हूं और विभिन्न तरीकों के बारे में सोच रहा था जिसे हमें .NET में इन दो तरीकों को लागू करना है। आपकी पसंदीदा रणनीति क्या है?बराबर और GetHashCode के लिए सबसे अच्छी रणनीति क्या है?

यह मेरा वर्तमान कार्यान्वयन है:

public override bool Equals(object obj) 
    { 
     var newObj = obj as MyClass; 

     if (null != newObj) 
     { 
      return this.GetHashCode() == newObj.GetHashCode(); 
     } 
     else 
     { 
      return base.Equals(obj); 
     } 
    } 

    //Since this is an entity I can use it´s Id 
    //When I don´t have an Id I usually make a composite key of the properties 
    public override int GetHashCode() 
    { 
     return String.Format("MyClass{0}", this.Id.ToString()).GetHashCode(); 
    } 
+0

संबंधित: http://stackoverflow.com/questions/2326288/implementing-ddd-entity-class-in-c –

+8

आप अपने बराबर में ही निर्धारक के रूप में GetHashCode के परिणामों का प्रयोग नहीं कर सकते हैं - हैश कोड हो सकता है वही वस्तुएं अलग होती हैं। आप अपने आईडी को बराबर में तुलना करने से बेहतर होगा। इस पर और अधिक के लिए, देखें [सी # में बराबर विधि ओवरराइड होने पर GetHashCode को ओवरराइड करना क्यों महत्वपूर्ण है?] (Http://stackoverflow.com/questions/371328/why-is-it-important-to-override-gethashcode- जब-बराबर-विधि-है-ओवर्रिडेन-इन-सी) –

+0

आपको यह ध्यान में रखना चाहिए कि GetHashCode() को कोड में अधिकतर उपयोग किया जाता है जहां प्रदर्शन महत्वपूर्ण है (ओ (1) लुकअप आदि के साथ सूचियां)। आपका कार्यान्वयन पहले से ही धीमा है, लेकिन आप इसे बिना किसी बदलाव के पहले से तेज कर सकते हैं: 'वापसी ("MyClass" + this.Id) .GetHashCode();' (केवल कुछ जो आप GetHashCode के साथ ध्यान में रखना चाहते हैं) – Aidiakapi

उत्तर

3

यह मानते हुए कि उदाहरणों क्योंकि हैश कोड हैं बराबर गलत है बराबर हैं।

मुझे लगता है कि GetHashCode अपने क्रियान्वयन ठीक है, लेकिन मैं आम तौर पर इस के लिए इसी तरह की बातों का उपयोग करें:

public override int GetHashCode() { 
    return object1.GetHashCode^intValue1^(intValue2 << 16); 
} 
+1

मुझे यह पुराना सवाल पता है, लेकिन क्या आपने यहां अभिव्यक्ति के बारे में समझाया है जिसका आपने उपयोग किया है – skjagini

+0

@skjagini: देखें [^ ऑपरेटर] (http://msdn.microsoft.com/en-us/library/zkacc7k1.aspx) - विशिष्ट या, और [<< ऑपरेटर] (http://msdn.microsoft.com/en-us/library/a1sway8w.aspx) - बाएं शिफ्ट। एकल हैशकोड प्राप्त करने के लिए कई संख्यात्मक मानों को एक साथ जोड़ने के कई तरीके हैं। विशेष या प्रभावी ढंग से twiddles बिट्स; हालांकि इसमें कुछ कमजोरियां हैं। GetHashCode कार्यान्वयन के लिए खोजें, जैसे कि [यह SO पोस्ट] (http://stackoverflow.com/questions/263400/what-is-the-best-algorithm-for-an-overridden-system-object-gethashcode?lq=1)। –

2

Hashcodes तो टकराने कर सकते हैं मुझे नहीं लगता कि वे समानता तुलना करने के लिए एक अच्छा तरीका है। आपको अंतर्निहित मानों की तुलना करनी चाहिए जो वस्तुओं को "बराबर" बनाते हैं। @Jon Skeet के इस प्रश्न का उत्तर देखें: What is the best algorithm for an overridden System.Object.GetHashCode? बेहतर गेटहाशकोड कार्यान्वयन के लिए यदि आपकी समानता में कई गुण शामिल हैं। अगर यह सिर्फ एक ही संपत्ति है, तो आप इसे अपने हैशकोड का पुन: उपयोग कर सकते हैं।

+0

आप सही हैं, लेकिन मेरी राय में, बहुत चौकस। हैश कोड समानता निर्धारित करने के लिए उपयुक्त नहीं हैं। समान वस्तुओं में एक ही हैश कोड होना चाहिए, लेकिन एक ही हैश कोड विभिन्न वस्तुओं द्वारा साझा किया जा सकता है। जैसा कि आप कहते हैं, वे टकरा सकते हैं। –

30

Domain-Driven Designसंस्थाओं और मूल्य ऑब्जेक्ट्स के बीच अंतर बना देता है। यह देखने के लिए एक अच्छा भेद है क्योंकि यह गाइड करता है कि आप बराबर कैसे कार्यान्वित करते हैं। अगर उनकी आईडी एक दूसरे के बराबर

संस्थाओं बराबर हैं।

वैल्यू ऑब्जेक्ट बराबर हैं यदि उनके सभी (महत्वपूर्ण) घटक तत्व एक-दूसरे के बराबर हैं।

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

+0

क्या आप ** संस्थाओं पर 'समान()' विधि रखने के लाभ को स्पष्ट करने के बारे में सोचेंगे जो आईडी की तुलना करता है? उपयोग के मामले क्या हैं? मैंने पूछा [एसओ पर एक समान सवाल] [http://stackoverflow.com/q/31533276/219187), लेकिन अब तक मुझे कोई जवाब नहीं मिला है जो स्पष्ट रूप से बताता है कि आईडी द्वारा इकाइयों की तुलना क्यों की जानी चाहिए। – theDmi

+0

@theDmi - कारण यह है कि एक इकाई की परिभाषा विशेष रूप से इसे अद्वितीय और पहचान योग्य, और संभवतः सिस्टम-नियंत्रित के रूप में संदर्भित करती है। कम से कम एक इकाई के लिए, जिसमें मूल रूप से डेटा बदलने के लिए डेटा और विधियां होती हैं, प्रत्येक इकाई में एक पहचानकर्ता होगा, और यह पहचानकर्ता अद्वितीय होगा। यदि मैं एक ही डेटा के साथ दस इकाइयां बनाता हूं और उन्हें बनाने के लिए एक ही कॉल करता हूं, तो पहचान एकमात्र चीज होगी जो अद्वितीय है। यही कारण है कि इवांस का कहना है कि प्रणाली पहचान के निर्माण को नियंत्रित कर सकती है। निजी तौर पर, मैं हमेशा इकाई को इसका समर्थन करने के लिए पहचानकर्ता बना देता हूं। –

3

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

public override bool Equals(object obj) 
{ 
    var myClass = obj as MyClass; 

    if (null != myClass) 
    { 
     // Order these by the most different first. 
     // That is, whatever value is most selective, and the fewest 
     // instances have the same value, put that first. 
     return this.Id == myClass.Id 
     && this.Name == myClass.Name 
     && this.Quantity == myClass.Quantity 
     && this.Color == myClass.Color; 
    } 
    else 
    { 
     // Not sure this makes sense! 
     return base.Equals(obj); 
    } 
} 

public override int GetHashCode() 
{ 
    int hash = 19; 
    unchecked { // allow "wrap around" in the int 
     hash = hash * 31 + this.Id; // assuming integer 
     hash = hash * 31 + this.Name.GetHashCode(); 
     hash = hash * 31 + this.Quantity; // again assuming integer 
     hash = hash * 31 + this.Color.GetHashCode(); 
    } 
    return hash; 
} 

इस के पीछे तर्क से कुछ के लिए this answer by Jon Skeet देखें। Xor का उपयोग करना अच्छा नहीं है क्योंकि डेटा के विभिन्न सेट समाप्त हो सकते हैं जिसके परिणामस्वरूप एक ही हैश होता है। प्राइम के साथ इस लपेटने वाली विधि (ऊपर 1 9 और 31 के बीज मूल्य, या आपके द्वारा चुने गए अन्य मूल्य) "बाल्टी" में विभाजित करने का बेहतर काम करते हैं जिनमें प्रत्येक टकराव होते हैं।

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

इसके अलावा, मुझे विश्वास है आपके Equals कार्यान्वयन किसी भी समझ में आता है कि नहीं कर रहा हूँ। जब समानता के लिए दो वस्तुओं की तुलना की जाती है, तो पहले उनके GetHashCode मानों की तुलना की जाती है। केवल अगर वे अलग हैं Equals विधि रन (ताकि यदि दो वस्तुओं को एक ही मान के लिए हैश अलग हैं, तो यह पता लगाया जाएगा)।चूंकि आपका GetHashCode कार्यान्वयन base का संदर्भ नहीं देता है, इसलिए ऐसा करने के लिए आपके Equals विधि का कोई अर्थ नहीं है।

संबंधित मुद्दे