2015-06-04 9 views
6

मैं एक सूची है (सटीक होना करने के लिए System.Collections.Immutable से ImmutableHashSet<ListItem>) आधार मदों की और निम्नलिखित कोडImmutableHashSet .Contains रिटर्न झूठी

_baseList.Contains(derivedItem) 

फोन करने की कोशिश, लेकिन इस झूठी देता है।

हालांकि निम्नलिखित कोड लाइनों सब लौट सच

object.ReferenceEquals(_baseList.First(), derivedItem) 
object.Equals(_baseList.First(), derivedItem) 
_baseList.First().GetHashCode() == derivedItem.GetHashCode() 

मैं भी निम्नलिखित लिख सकते हैं और यह सच रिटर्न:

_baseList.OfType<DerivedClass>().Contains(derivedItem) 

हूँ क्या मैं गलत कर रही है, मैं चाहते हैं ओफटाइप सामान लिखने से बचें।

संपादित करें:

private ImmutableHashSet<BaseClass> _baseList; 

public class BaseClass 
{ 

} 

public class DerivedClass : BaseClass 
{ 

} 

public void DoStuff() 
{ 
    var items = _baseList.OfType<DerivedClass>().ToList(); 
    foreach (var derivedItem in items) 
    { 
     RemoveItem(derivedItem); 
    } 
} 

public void RemoveItem(BaseClass derivedItem) 
{ 
    if (_baseList.Contains(derivedItem)) 
    { 
     //doesn't reach this place, since _baseList.Contains(derivedItem) returns false... 
     _baseList = _baseList.Remove(derivedItem); 
    } 

    //object.ReferenceEquals(_baseList.First(), derivedItem) == true 
    //object.Equals(_baseList.First(), derivedItem) == true 
    //_baseList.First().GetHashCode() == derivedItem.GetHashCode() == true 
    //_baseList.OfType<DerivedClass>().Contains(derivedItem) == true 
} 

EDIT2:

यहाँ मेरी समस्या का एक प्रतिलिपि प्रस्तुत करने योग्य कोड, ImmutableHashSet<> कैश GetHashCode की तरह लगता है और वर्तमान GetHashCode सूची के अंदर प्रविष्टियों के साथ तुलना नहीं है , ImmutableHashSet<> बताने का कोई तरीका है कि आइटम के GetHashCode आइटम अलग-अलग हो सकते हैं, कम से कम उस आइटम के लिए जो मैं वर्तमान में जांच रहा हूं क्योंकि यह वही संदर्भ है ...

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     private static ImmutableHashSet<BaseClass> _baseList; 

     static void Main(string[] args) 
     { 
      _baseList = ImmutableHashSet.Create<BaseClass>(); 
      _baseList = _baseList.Add(new DerivedClass("B1")); 
      _baseList = _baseList.Add(new DerivedClass("B2")); 
      _baseList = _baseList.Add(new DerivedClass("B3")); 
      _baseList = _baseList.Add(new DerivedClass("B4")); 
      _baseList = _baseList.Add(new DerivedClass("B5")); 

      DoStuff(); 
      Console.WriteLine(_baseList.Count); //output is 5 - put it should be 0... 
      Console.ReadLine(); 
     } 

     private static void DoStuff() 
     { 
      var items = _baseList.OfType<DerivedClass>().ToList(); 
      foreach (var derivedItem in items) 
      { 
       derivedItem.BaseString += "Change..."; 
       RemoveItem(derivedItem); 
      } 
     } 

     private static void RemoveItem(BaseClass derivedItem) 
     { 
      if (_baseList.Contains(derivedItem)) 
      { 
       _baseList = _baseList.Remove(derivedItem); 
      } 
     } 
    } 

    public abstract class BaseClass 
    { 
     private string _baseString; 
     public string BaseString 
     { 
      get { return _baseString; } 
      set { _baseString = value; } 
     } 

     public BaseClass(string baseString) 
     { 
      _baseString = baseString; 
     } 

     public override int GetHashCode() 
     { 
      unchecked 
      { 
       int hashCode = (_baseString != null ? _baseString.GetHashCode() : 0); 
       return hashCode; 
      } 
     } 
    } 
    public class DerivedClass : BaseClass 
    { 
     public DerivedClass(string baseString) 
      : base(baseString) 
     { 

     } 
    } 
} 

अगर मैं बदल जाएगा ImmutableHashSet<>ImmutableList<> करने के लिए कोड ठीक काम करता है, इसलिए यदि आप लोग किसी भी अच्छा विचार मैं इस सूची में बदल जाएगा के साथ नहीं आते हैं।

+1

लेकिन यह सिर्फ असफल नहीं होता है क्योंकि बेसलिस्ट 'ListItem' से भरा हुआ है और आप जिस वस्तु को खोज रहे हैं वह है' DerivedClass' – EaterOfCode

+0

@EaterOfCode DerivedClass बेसक्लास से निकला है। –

+0

@EaterOfCode और यदि सूची में कोई DerivedClass ऑफ़ टाइप टाइप नहीं होगा <>()। इसमें भी झूठी वापसी होगी, जो मामला नहीं है। –

उत्तर

4

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

private static void DoStuff() 
    { 
     var items = _baseList.OfType<DerivedClass>().ToList(); 
     foreach (var derivedItem in items) 
     { 
      derivedItem.BaseString += "Change..."; 
      RemoveItem(derivedItem); 
     } 
    } 

    private static void RemoveItem(BaseClass derivedItem) 
    { 
     if (_baseList.Contains(derivedItem)) 
     { 
      _baseList = _baseList.Remove(derivedItem); 
     } 
    } 

RemoveItem() में _baseList.Contains(), क्योंकि आप संग्रहीत आइटम की पहचान बदल गया है - अपने BaseString संपत्ति:

इस कोड को नहीं काम करने के लिए जा रहा है ।

+0

मैंने इसे अब तक समझा, जब मैंने देखा कि क्या हो रहा था, तो मूल रूप से मेरा सवाल अभी सूची के अलावा इसके आसपास एक रास्ता है? आपका उत्तर इसका तात्पर्य है लेकिन हो सकता है कि आप अग्रिम में अधिक प्रत्यक्ष हाँ या धन्यवाद दे सकें। :) –

+0

@RandRandom आप संग्रह में वस्तुओं को क्यों बदल रहे हैं (जिस तरीके से उनकी पहचान बदलती है) पहली जगह में? – Servy

+2

@RandRandom - यदि आप हैश ऑब्जेक्ट को संशोधित करना चाहते हैं, तो आपको इसे हैशिंग डेटा संरचना से हटा देना होगा, इसे संशोधित करना होगा, और इसे फिर से जोड़ना होगा। हालांकि ऐसा करने के लिए वास्तव में यह बुरा व्यवहार है। और यदि आपके पास एक बड़ा कार्यक्रम है और इन ऑब्जेक्ट्स को पूरे स्थान पर पारित किया गया है, और आप ऑब्जेक्ट की पहचान में संशोधन की अनुमति देते हैं, तो आप विफलता के लिए स्वयं को सेट कर रहे हैं क्योंकि कोड के कुछ असंबंधित टुकड़े बिना किसी सूचना के हैश ऑब्जेक्ट को संशोधित कर सकते हैं हैशिंग डेटा संरचना के मालिक। – antiduh

3

मुझे लगता है कि आपने अपने संपादन में अपने प्रश्न का उत्तर दिया है। एक बार जब आप हैशसेट में आइटम जोड़ते हैं तो आपके पास हैशकोड परिवर्तन नहीं हो सकता है। यह हैशसेट काम करता है के अनुबंध को तोड़ देता है।

विषय पर अधिक जानकारी के लिए this excellent article by Eric Lippert देखें।

विशेष रूप से, यह कहते हैं निम्नलिखित:

दिशानिर्देश: पूर्णांक GetHashCode द्वारा दिया

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

हालांकि, यह केवल एक आदर्श स्थिति दिशानिर्देश है; वास्तविक नियम है:

नियम: पूर्णांक GetHashCode द्वारा वापस कभी नहीं बदल चाहिए, जबकि वस्तु एक डेटा संरचना है कि शेष हैश कोड पर निर्भर करता है में निहित है स्थिर

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

तो एक वस्तु के हैश कोड उत्परिवर्तित कर सकते हैं, जबकि यह हैश तालिका में है तो स्पष्ट रूप से शामिल विधि कार्य करना बंद कर। आपने ऑब्जेक्ट को बाल्टी # 5 में रखा है, आप इसे म्यूटेट करते हैं, और जब आप सेट से पूछते हैं कि इसमें म्यूटेटेड ऑब्जेक्ट है, तो यह बाल्टी # 74 में दिखता है और इसे नहीं मिला।

याद रखें, ऑब्जेक्ट्स को हैश टेबल में रखा जा सकता है जिसकी आपने अपेक्षा नहीं की थी। बहुत सारे LINQ अनुक्रम ऑपरेटर आंतरिक रूप से हैश टेबल का उपयोग करते हैं। एक LINQ क्वेरी की गणना करते समय खतरनाक रूप से उत्परिवर्तनीय वस्तुओं को न चलाएं जो उन्हें वापस लाता है!

संपादित: Btw, आपकी पोस्ट करने और अपने बाद के संपादित क्यों तुम हमेशा शुरू से ही आपकी समस्या का पूरा और प्रतिलिपि प्रस्तुत करने योग्य काम कर कोड पोस्ट करना चाहिए का एक आदर्श उदाहरण है, बजाय बाहर फिल्टर करने के लिए आप क्या महसूस की कोशिश कर रहे हैं अप्रासंगिक जानकारी है। एक घंटे पहले आपकी पोस्ट को देखने वाले बहुत से लोग आपको एक अलग दूसरे में सही जवाब दे सकते थे, जिसमें उनके पास सभी प्रासंगिक जानकारी शुरू होनी थीं।

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