2010-05-12 19 views
12

पृष्ठभूमि: मैंने नेस्टेड कक्षा एन के साथ नेस्टेड कक्षा एन के साथ संलग्न किया है। एन में एन के कई उदाहरणों के साथ। संलग्न (पैरेंट) कक्षा में मैं कुछ गणना कर रहा हूं और मैं नेस्टेड क्लास के प्रत्येक उदाहरण के लिए मान निर्धारित कर रहा हूं। कुछ ऐसा:नेस्टेड क्लास के निजी सदस्यों तक पहुंच कैसे प्राप्त करें?

n1.field1 = ...; 
n1.field2 = ...; 
n1.field3 = ...; 
n2.field1 = ...; 
... 

यह एक बड़ी eval विधि (मूल वर्ग में) है। मेरा इरादा है - चूंकि सभी गणना मूल वर्ग में हैं (वे प्रति घोंसला प्रति उदाहरण नहीं कर सकते हैं क्योंकि यह कोड को और अधिक जटिल बना देगा) - सेटर्स को केवल मूल वर्ग और गेटर्स सार्वजनिक के लिए उपलब्ध कराएं।

और अब वहाँ एक समस्या है:

  • जब मैं setters निजी बनाने, माता पिता के वर्ग उन्हें
  • acces नहीं कर सकते जब मैं उन्हें सार्वजनिक, हर कोई मान
  • बदल सकते हैं बनाने के लिए और सी # नहीं मित्र अवधारणा
  • मैं कन्स्ट्रक्टर में मूल्यों को पास नहीं कर सकता क्योंकि आलसी मूल्यांकन तंत्र का उपयोग किया जाता है (इसलिए उन्हें संदर्भित करते समय उदाहरण बनाए जाना चाहिए - मैं सभी ऑब्जेक्ट्स बनाता हूं और गणना मांग पर ट्रिगर होती है)

मैं अटक गया हूं - यह कैसे करें (मूल वर्ग तक पहुंच सीमित करें, और नहीं, कम नहीं)?


मुझे लगता है मैं पहले उत्तर-प्रश्न मिलेगा - "लेकिन आप प्रत्येक क्षेत्र प्रति मूल्यांकन क्यों विभाजित नहीं है" - तो मैं उदाहरण के द्वारा इस का जवाब: कैसे आप न्यूनतम और अधिकतम की गणना करते हैं संग्रह का मूल्य? एक तेज़ तरीके से? जवाब है - एक पास में। यही कारण है कि मेरे पास एक eval फ़ंक्शन है जो गणना करता है और सभी फ़ील्ड को एक साथ सेट करता है।

+0

क्या आंतरिक कीवर्ड पर्याप्त नहीं है? – Kimi

+3

यह बहुत अधिक है :-)। – greenoldman

+0

आप अपने सहकर्मियों पर भरोसा नहीं करते? –

उत्तर

7

यदि आपके लिए माता-पिता और बाल कक्षाओं को किसी अन्य असेंबली में रखना संभव है, तो आप सेटर्स के लिए internal का उपयोग कर सकते हैं। आम तौर पर जंगली में इसका सामना कैसे किया जाता है।

संपादित:

Thomas Levesque's answer मुझे एक विचार दिया:

class Program 
{ 
    static void Main(string[] args) 
    { 
     E myE = new E(); 

     Console.WriteLine("E.N1.Field1 = " + myE.N1.Field1); 
     Console.WriteLine("E.N2.Field1 = " + myE.N2.Field1); 
    } 

    public interface IN 
    { 
     int Field1 { get; } 
    } 

    public class E 
    { 
     private N _n1 = new N(); 
     private N _n2 = new N(); 

     public E() 
     { 
      _n1.Field1 = 42; 
      _n2.Field1 = 23; 
     } 

     public IN N1 
     { 
      get { return _n1; } 
     } 

     public IN N2 
     { 
      get { return _n2; } 
     } 

     private class N : IN 
     { 
      private int _field1; 

      public int Field1 
      { 
       get { return _field1; } 
       set { _field1 = value; } 
      } 
     } 
    } 
} 

आप कैसे बच्चे वर्ग N बेनकाब करने की जरूरत है, इस काम कर सकता था पर निर्भर करता है।

+1

धन्यवाद, लेकिन यह एक एकल फ़ाइल है, इतना बड़ा नहीं, इसलिए यह इस अलग असेंबली को सेट करने के लिए ओवरकिल की तरह लगता है। – greenoldman

+0

थॉमस लेवेस्क के उत्तर के आधार पर मेरा उत्तर अपडेट किया गया। – Codesleuth

+0

सौंदर्य (इंटरफेस घोंसला जा सकता है)।धन्यवाद! – greenoldman

-2

क्षेत्रों "आंतरिक संरक्षित"

अगर नेस्टेड कक्षाएं आप उन क्षेत्रों के लिए इस्तेमाल कर सकते हैं obly "आंतरिक" निजी रहे हैं।

+0

क्या खेतों को पूरे असेंबली के संपर्क में नहीं लाया जाएगा? "आंतरिक क्षेत्र और निजी वर्ग" के मामले में – greenoldman

+0

: नहीं क्योंकि कक्षा निजी है। अन्य मामला: हाँ यह होगा। लेकिन स्वयं की असेंबली आपके नियंत्रण में होनी चाहिए। आमतौर पर यह कोई समस्या नहीं है। – Jack

+3

वास्तव में यह हमेशा एक समस्या है - एक साल बाद, आप एक ही सर्वोत्तम इरादा रख सकते हैं, लेकिन आप डिज़ाइन को भूल सकते हैं। कोड डिज़ाइन को प्रतिबिंबित करना चाहिए, टिप्पणियों या इच्छाओं पर नहीं। – greenoldman

42

आप E के अंदर एक निजी इंटरफ़ेस IN घोषित कर सकते हैं, स्पष्ट रूप से N द्वारा कार्यान्वित किया गया। इस इंटरफ़ेस केवल E द्वारा N सुलभ के सदस्यों का पर्दाफाश होगा:

public class E 
{ 
    public void Foo() 
    { 
     IN n = new N(); 
     n.Field1 = 42; 
    } 

    public class N : IN 
    { 
     private int _field1; 

     int IN.Field1 
     { 
      get { return _field1; } 
      set { _field1 = value; } 
     } 
    } 

    private interface IN 
    { 
     int Field1 { get; set; } 
    } 
} 
+0

धन्यवाद। इंटरफ़ेस को निजी नहीं बनाया जा सकता है क्योंकि मैं अभिभावक वर्ग (मुझे सार्वजनिक गेटर्स की आवश्यकता है) के बाहर के मूल्यों को नहीं पढ़ेगा, और एक बार जब यह सार्वजनिक हो जाए तो मैं सार्वजनिक रूप से सेटर्स का भी उपयोग कर सकता हूं। – greenoldman

+2

मुझे लगता है कि आपने मेरा जवाब गलत समझा है ... 'IN' इंटरफ़ेस कभी सार्वजनिक होने का इरादा नहीं है। यह केवल नेस्टेड क्लास के लिए केवल एक वर्ग के गुणों का पर्दाफाश करने का एक तरीका है। यदि आपको –

+0

की आवश्यकता है तो आप 'N' में सार्वजनिक गेटर्स भी बना सकते हैं यदि इंटरफ़ेस निजी है तो यह मूल वर्ग के बाहर उपलब्ध नहीं है। – greenoldman

4

एक अन्य विकल्प के सदस्यों आप निजी होना चाहते छोड़ने के लिए है सार्वजनिक अगर आपके (नेस्टेड) ​​वर्ग निजी है। यदि निजी वर्ग के क्षेत्र सार्वजनिक हैं, तो यह केवल संलग्न वर्ग के संपर्क में जा रहा है।

public class E 
{ 
    public void Foo() 
    { 
     IN n = new N(); 
     n.field1 = 42; 
    } 

    class N : IN 
    { 
     public int _field1; 
    } 
} 

अब NE सार्वजनिक केवल मामलों जा रहा है केवल E को दिखाई देती है, तो n._field1, और आप सुरक्षित हैं ..

1

यह एक पुरानी सवाल है, लेकिन यहाँ एक संभव समाधान है कि 'नहीं करता चला जाता है इंटरफेस का उपयोग नहीं करते हैं।

public class Outer { 
    private delegate void _operateDlg(Inner inner, bool value); 
    private static _operateDlg _validate; 

    static Outer() { 
     Inner.Init(); 
    } 

    public void Set(Inner inner, bool value) { 
     _validate(inner, value); 
    } 

    public class Inner { 
     public bool IsValid {get; private set; } 
     public static void Init() { 
      Outer._validate += delegate(Inner i, bool value) { 
       i.IsValid = value; 
      }; 
     } 
    } 
} 

आप बाहरी वर्ग है कि आप के साथ आवंटित में विभिन्न प्रतिनिधियों के सभी प्रकार के रख सकते हैं:

आप आंतरिक वर्ग जो अप, बाहरी कक्षा में प्रतिनिधियों सेट इतना की तरह में एक स्थिर कार्य हो सकता है Inner.Init() विधि, जैसे विधियों जो एक निजी कन्स्ट्रक्टर या किसी विशेष क्षेत्र के गेटर्स/सेटर्स के माध्यम से इनर क्लास का उदाहरण लौटाती हैं।

यदि आपको अपनी आंतरिक कक्षा में एक अतिरिक्त Init() स्थिर कार्य करने में कोई फर्क नहीं पड़ता है, तो इसे बदलने की ज़रूरत नहीं है। लेकिन अगर आप Init() विधि दिखाई दे सकता है नहीं करना चाहते, तो आप इसे कॉल करने के लिए प्रतिबिंब का उपयोग कर सकते हैं:

using System.Reflection; 

public class Outer { 
    private delegate void _operateDlg(Inner inner, bool value); 
    private static _operateDlg _validate; 

    static Outer() { 
     typeof(Inner).GetMethod("Init", 
      BindingFlags.Static | BindingFlags.NonPublic).Invoke(null, null); 
    } 

    public void Set(Inner inner, bool value) { 
     _validate(inner, value); 
    } 

    public class Inner { 
     public bool IsValid {get; private set; } 
     private static void Init() { 
      Outer._validate = delegate(Inner i, bool value) { 
       i.IsValid = value; 
      }; 
     } 
    } 
} 

मुझे पता है कि एक वैसे भी निजी उपयोग प्रतिबंध बायपास करने के लिए प्रतिबिंब इस्तेमाल कर सकते हैं, लेकिन यह सिर्फ करने के लिए उपयोग एक एकल इनिट() विधि को कॉल करें जो उचित प्रतिनिधियों को असाइन करता है, मेरी राय में एक बहुत साफ और अधिक बहुमुखी समाधान है। विकल्प प्रत्येक एकल प्रतिनिधि के लिए प्रतिबिंब बुलाएगा जिसे आप बनाना चाहते हैं, और फिर भी सीमाएं हो सकती हैं (जैसे कि रचनाकारों को प्रतिनिधियों को बनाने में असमर्थता)।

उपर्युक्त समाधान न केवल रैपिंग कन्स्ट्रक्टर का समर्थन करता है, बल्कि यह केवल कार्यक्रम के जीवनकाल में प्रतिबिंब का उपयोग करेगा, इसलिए इस तथ्य के अलावा कोई उल्लेखनीय प्रदर्शन दंड नहीं होना चाहिए कि आप प्रतिनिधियों का उपयोग करने के लिए प्रतिनिधियों का उपयोग कर रहे हैं पहली जगह में प्रत्यक्ष पहुंच के रूप में अनुमति दी जानी चाहिए। मुझे नहीं पता कि क्यों सी # इसका समर्थन नहीं करता है, और मैं एक अच्छे कारण के बारे में नहीं सोच सकता कि ऐसा क्यों नहीं करता है।

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