2012-03-14 28 views
9

के लिए सी # मैं अपने स्वयं Equals() और GetHashCode() अक्सर अधिभावी अर्थ है कि समान संपत्ति मूल्यों के साथ व्यापार की वस्तुओं के बराबर हैं लागू करने के लिए लगता है। इससे कोड को जन्म दिया जाता है जो लिखने के लिए दोहराया जाता है और बनाए रखने के लिए नाजुक होता है (संपत्ति जोड़ दी जाती है और एक/दोनों ओवरराइड अपडेट नहीं होते हैं)। कार्यान्वयन पद्धति ध्वनि हैसरल अधिभावी बराबर(), GetHashCode() में बेहतर अनुरक्षणीयता

public override bool Equals(object obj) 
{ 
    if (object.ReferenceEquals(this, obj)) return true; 

    MyDerived other = obj as MyDerived; 

    if (other == null) return false; 

    bool baseEquals = base.Equals((MyBase)other); 
    return (baseEquals && 
     this.MyIntProp == other.MyIntProp && 
     this.MyStringProp == other.MyStringProp && 
     this.MyCollectionProp.IsEquivalentTo(other.MyCollectionProp) && // See http://stackoverflow.com/a/9658866/141172 
     this.MyContainedClass.Equals(other.MyContainedClass)); 
} 

public override int GetHashCode() 
{ 
    int hashOfMyCollectionProp = 0; 
    // http://computinglife.wordpress.com/2008/11/20/why-do-hash-functions-use-prime-numbers/ 
    // BUT... is it worth the extra math given that elem.GetHashCode() should be well-distributed? 
    int bitSpreader = 31; 
    foreach (var elem in MyCollectionProp) 
    { 
     hashOfMyCollectionProp = spreader * elem.GetHashCode(); 
     bitSpreader *= 31; 
    } 
    return base.GetHashCode()^//^is a good combiner IF the combined values are well distributed 
     MyIntProp.GetHashCode()^
     (MyStringProp == null ? 0 : MyStringProp.GetHashValue())^
     (MyContainedClass == null ? 0 : MyContainedClass.GetHashValue())^
     hashOfMyCollectionProp; 
} 

मेरे प्रश्न

  1. :

    कोड कुछ इस तरह लग रही समाप्त होता है (कार्यान्वयन पर टिप्पणियों का स्वागत है)?

  2. क्या पर्याप्त है कि योगदान घटक मूल्य अच्छी तरह से वितरित किए जाते हैं? क्या मुझे अपने हैश दिए गए संग्रह तत्वों को संयोजित करते समय 31-से-द-एन तक गुणा करने की आवश्यकता है?
  3. ऐसा लगता है कि यह कोड कोड में सारणित किया जा सकता है जो सार्वजनिक गुणों को निर्धारित करने के लिए प्रतिबिंब का उपयोग करता है, एक अभिव्यक्ति वृक्ष बनाता है जो हाथ से कोडित समाधान से मेल खाता है, और अभिव्यक्ति के पेड़ को आवश्यकतानुसार निष्पादित करता है। क्या वह दृष्टिकोण उचित लगता है? क्या कोई मौजूदा कार्यान्वयन कहीं है?
+2

होना चाहिए क्यों (पोस्टिंग के बाद एक वर्ष से अधिक) downvote? सवाल बहुत वैध है। अगर इसमें कुछ गड़बड़ है, तो कृपया क्या कहें। –

उत्तर

4

MSDN वास्तव में कहना नहीं करता है "अधिभार परिवर्तनशील प्रकार के लिए एट अल के बराबर नहीं है"। ऐसा नहीं है कि कहा करते थे, लेकिन अब यह कहते हैं:

जब आप एक वर्ग या struct को परिभाषित, आप तय है कि क्या यह समझ में आता है प्रकार के लिए मूल्य समानता (या तुल्यता) के एक कस्टम परिभाषा बनाने के लिए। आम तौर पर, आप मान समानता लागू करते हैं जब प्रकार की वस्तुओं को किसी प्रकार के संग्रह में जोड़ा जाने की उम्मीद है, या उनका प्राथमिक उद्देश्य फ़ील्ड या गुणों का एक सेट स्टोर करना है।

http://msdn.microsoft.com/en-us/library/dd183755.aspx

फिर भी, हैश कोड की स्थिरता आसपास है, जबकि एक वस्तु एक टुकड़े किए गए संग्रह (Dictionary<T,U>, HashSet<T>, आदि) में भाग लेता है जटिलताओं हैं।

मैं, के रूप में यहां उल्लिखित दोनों दुनिया का सबसे अच्छा के लिए चुनते करने का फैसला किया:

https://stackoverflow.com/a/9752155/141172

1

मैं अपने स्वयं अधिभावी बराबर लगता है() और GetHashCode() अक्सर

  • MSDN कहते हैं: कर अधिभार परिवर्तनशील प्रकार

के लिए एट अल के बराबर नहीं^^ पर्याप्त दिया गया है कि योगदान घटक मूल्य अच्छी तरह से वितरित कर रहे हैं?

  • हाँ, पर हे हमेशा अच्छी तरह से वितरित नहीं कर रहे हैं। int गुणों पर विचार करें। कुछ (छोटे) प्राइम नंबरों के साथ स्थानांतरण की सलाह दी जाती है।
+0

एमएसडीएन कहां कहता है? मैंने पाठ को सचमुच गुग करने की कोशिश की और केवल यह प्रश्न पाया। –

+0

इसके अलावा ... एक सरल उदाहरण लेने के लिए जहां मैं बराबर ओवरराइड करने में उपयोगिता देखता हूं (लेकिन शायद मुझे कुछ याद आ रहा है), आप एक यूनिट टेस्ट को कैसे कार्यान्वित करेंगे जो 'माईडेरिव अपेक्षित = नया MyDerived() {/* प्रारंभ * /}; MyDerived वास्तविक = DoSomeTest(); Assert.AreEqual (अपेक्षित, वास्तविक) '? –

+0

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

0

शायद मैं यहाँ उलझन में हूँ, लेकिन नहीं null चेक पर 1 लौटाना चाहिए 0 के बजाय GetHashCode ओवरराइड में?

तो

MyStringProp == null ? 0 : MyStringProp.GetHashValue() 

MyStringProp == null ? 1 : MyStringProp.GetHashValue()