2010-06-16 10 views
12

मेरी सी # -Project में के लिए हटाएँ, मैं एक वर्ग एक सूचीसार्वजनिक जोड़ें ना करे और एक सूची <T>

public class MyClass 
{ 
    public MyClass parent; 
    public List<MyClass> children; 
    ... 
} 

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

कोई विचार यह है कि अपने स्वयं के आईएलआईस्ट को लागू करने के अलावा इसे कैसे करें?

अग्रिम धन्यवाद, फ्रैंक

+0

संभावित डुप्लिकेट [मैं सूची की सी # में विधि जोड़ने के तरीके को ओवरराइड कैसे करूं?] (Http://stackoverflow.com/questions/580202/how-to-i-override-listts-add-method-in- सी) –

उत्तर

28

यदि आप कॉलर को List<T> पर रखते हैं, तो आप इसे नियंत्रित नहीं कर सकते; आप List<T> को उपclass भी नहीं कर सकते हैं, क्योंकि जोड़ें/निकालें virtual नहीं हैं।

इसके बजाय, तो, मैं डेटा IEnumerable<MyClass> के रूप में बेनकाब होगा:

private readonly List<MyClass> children = new List<MyClass>(); 
public void AddChild(MyClass child) {...} 
public void RemoveChild(MyClass child) {...} 
public IEnumerable<MyClass> Children { 
    get { 
     foreach(var child in children) yield return child; 
    } 
} 

LINQ वे करने के लिए (yield return से बचाता है उन्हें बस इसे कास्टिंग)

फोन करने वाले अभी भी .Children पर foreach उपयोग कर सकते हैं, और धन्यवाद अन्य सभी मजेदार चीजें भी कर सकते हैं (Where, First, आदि)।

+0

आप हमेशा नए ऑपरेटर के साथ उन तरीकों को मुखौटा कर सकते हैं और उन्हें कुछ भी नहीं कर सकते हैं - लेकिन आप इस बिंदु से अपना स्वयं का कस्टम संग्रह भी कर सकते हैं :) –

+0

@Adam - यदि आप उन्हें 'नया' करते हैं, तो कॉलर पूरी तरह से कर सकता है अपने चर को सिर्फ 'सूची ' के रूप में टाइप करके अपने तरीकों को बाईपास करें। आपको सभी 'IList' और 'IList ' को फिर से कार्यान्वित करने की भी आवश्यकता होगी। इसके लायक नहीं। –

+3

आप 'foreach' /' उपज' लूप के बजाय '.AEnumerable() 'एक्सटेंशन विधि का भी उपयोग कर सकते हैं। http://msdn.microsoft.com/en-us/library/bb335435.aspx – spoulson

3

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

public class MyClass 
{ 
    public MyClass Parent { get; private set; } 

    private List<MyClass> _children = new List<MyClass>(); 
    public IEnumerable<MyClass> Children 
    { 
     get 
     { 
      // Using an iterator so that client code can't access the underlying list 
      foreach(var child in _children) 
      { 
       yield return child; 
      } 
     } 
    } 

    public void AddChild(MyClass child) 
    { 
     child.Parent = this; 
     _children.Add(child); 
    } 

    public void RemoveChild(MyClass child) 
    { 
     _children.Remove(child); 
     child.Parent = null; 
    } 
} 

वैसे, सार्वजनिक क्षेत्रों की घोषणा से बचें, क्योंकि आप नियंत्रित नहीं कर सकते कि क्लाइंट कोड उनके साथ क्या करता है।

0

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

यदि आप सूची के माध्यम से गणना करना चाहते हैं तो आपको अपना खुद का गणक बनाना होगा।

1
using System.Collections.ObjectModel; 

public class MyClass 
{ 
    private List<MyClass> children; 

    public ReadOnlyCollection<MyClass> Children 
    { 
     get 
     { 
      return new ReadOnlyCollection<MyClass>(children); 
     } 
    } 
} 
+0

यदि आप इस .children पर आइटम जोड़ते/हटाते हैं, तो readOnlyCollection इसकी वस्तुओं को प्राप्त करेगा, क्योंकि यह मूल सूची को आंतरिक रूप से संग्रहीत करता है ... –

0

आप इसे निजी बनाकर कक्षा में सूची संपुटित, और एक ReadOnlyCollection के रूप में पेश कर सकते हैं: कि जिस तरह से यह कर सकते हैं

public class MyClass { 

    public MyClass Parent { get; private set; }; 

    private List<MyClass> _children; 

    public ReadOnlyCollection<MyClass> Children { 
    get { return _children.AsReadOnly(); } 
    } 

    public void AddChild(MyClass item) { 
    item.Parent = this; 
    _children.Add(item); 
    } 

    public void DeleteChild(MyClass item) { 
    item.Parent = null; 
    _children.Remove(item); 
    } 

} 

आप Parent एक निजी सेटर के साथ एक संपत्ति कर सकते हैं, बाहर से संशोधित नहीं किया जाएगा, लेकिन AddChild और DeleteChild विधियां इसे बदल सकती हैं।

14

अपने IList<T> को लागू करने के अलावा आप ReadOnlyCollection<MyClass> वापस कर सकते हैं।

public MyClass 
{ 
    public MyClass Parent; 

    private List<MyClass> children; 
    public ReadOnlyCollection<MyClass> Children 
    { 
     get { return children.AsReadOnly(); } 
    } 
} 
+1

+1 सबसे साफ समाधान के लिए - हालांकि केवल एक आईनेमरेबल <> के रूप में उजागर करना लगभग उतना ही अच्छा है, तेज, और सरल। मेरे द्वारा –

+1

+1। मुझे बस कोड की सादगी के लिए यह पसंद है। KISS सिद्धांत! –

+0

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

0

List(T).AsReadOnly() का उपयोग करें।

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

रिटर्न एक IList < केवल पढ़ने के (के < (टी>)>) वर्तमान संग्रह के लिए आवरण।

.NET 2.0 के बाद से उपलब्ध है।

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