यह देखते हुए कि संग्रह एक सेट सदस्य के रूप में System.Collections.Generic.HashSet<>
स्वीकार null
करता है, कोई भी पूछ सकता है कि हैश कोड क्या null
होना चाहिए। ऐसा लगता है कि ढांचा उपयोग करता है 0
:
// nullable struct type
int? i = null;
i.GetHashCode(); // gives 0
EqualityComparer<int?>.Default.GetHashCode(i); // gives 0
// class type
CultureInfo c = null;
EqualityComparer<CultureInfo>.Default.GetHashCode(c); // gives 0
यह अशक्त Enums के साथ (थोड़ा) समस्याग्रस्त हो सकता है। अगर हम परिभाषित करते हैं
enum Season
{
Spring,
Summer,
Autumn,
Winter,
}
तब Nullable<Season>
(इसे भी कहा जाता है Season?
) केवल पांच मान ले सकते हैं, लेकिन उनमें से दो, अर्थात् null
और Season.Spring
, एक ही हैश कोड है।
यह इस तरह एक "बेहतर" समानता तुलना लिखने के लिए आकर्षक है:
class NewNullEnumEqComp<T> : EqualityComparer<T?> where T : struct
{
public override bool Equals(T? x, T? y)
{
return Default.Equals(x, y);
}
public override int GetHashCode(T? x)
{
return x.HasValue ? Default.GetHashCode(x) : -1;
}
}
लेकिन क्या कोई कारण है कि हैश कोड क्यों null
होना चाहिए 0
?
संपादित करें / अलावा:
कुछ लोगों को लगता है कि यह ओवरराइडिंग के बारे में है Object.GetHashCode()
। यह वास्तव में, वास्तव में नहीं है। (.NET के लेखकों के एक ओवरराइड बनाने के लिए किया था GetHashCode()
में Nullable<>
struct जो है , हालांकि प्रासंगिक,।) Parameterless का एक उपयोगकर्ता के प्रश्न के लिखित कार्यान्वयन GetHashCode()
स्थिति कभी नहीं संभाल कर सकते हैं जहां किसी चीज़ जिसका हैश कोड हम तलाश है null
।
यह अमूर्त विधि को EqualityComparer<T>.GetHashCode(T)
लागू करने या अन्यथा इंटरफ़ेस विधि को लागू करने के बारे में है IEqualityComparer<T>.GetHashCode(T)
। अब, MSDN के इन लिंक को बनाते समय, मैं देख रहा हूँ कि यह वहाँ कहता है कि ये विधियाँ फेंकती हैं ArgumentNullException
यदि उनका एकमात्र तर्क है null
। यह निश्चित रूप से MSDN पर एक गलती होनी चाहिए? .NET का कोई भी कार्यान्वयन अपवाद नहीं है। उस मामले में फेंकने से प्रभावी रूप से किसी को जोड़ने null
का प्रयास टूट जाएगा HashSet<>
। जब तक HashSet<>
एक null
वस्तु के साथ काम करते समय कुछ असाधारण नहीं होता है (मुझे यह परीक्षण करना होगा)।
नई संस्करण / प्रशंसा:
अब मैंने डिबगिंग की कोशिश की। इसके साथ HashSet<>
, मैं पुष्टि कर सकता हूं कि डिफ़ॉल्ट समानता तुलना के साथ, मान Season.Spring
और एक ही बाल्टी में समाप्त null
हो जाएंगे । यह बहुत ही सावधानी से निजी सरणी सदस्यों m_buckets
और निरीक्षण द्वारा निर्धारित किया जा सकता है m_slots
। ध्यान दें कि सूचकांक हमेशा डिजाइन द्वारा, एक से ऑफसेट होते हैं।
कोड मैंने ऊपर दिया है, हालांकि, इसे ठीक नहीं करते हैं। जैसा कि यह पता चला है, HashSet<>
जब मूल्य होता है तो समानता की तुलना भी कभी नहीं पूछेंगे null
। यह स्रोत कोड से है HashSet<>
:
// Workaround Comparers that throw ArgumentNullException for GetHashCode(null).
private int InternalGetHashCode(T item) {
if (item == null) {
return 0;
}
return m_comparer.GetHashCode(item) & Lower31BitMask;
}
इसका मतलब है कि, कम से कम HashSet<>
, के हैश को बदलना भी संभव नहीं है null
। इसके बजाय, एक समाधान इस तरह से अन्य सभी मूल्यों के हैश को बदलने के लिए है:
class NewerNullEnumEqComp<T> : EqualityComparer<T?> where T : struct
{
public override bool Equals(T? x, T? y)
{
return Default.Equals(x, y);
}
public override int GetHashCode(T? x)
{
return x.HasValue ? 1 + Default.GetHashCode(x) : /* not seen by HashSet: */ 0;
}
}