2009-04-27 11 views
8

हां, तो वस्तु initializers काम के सभी प्रकार हैं - यदि आप LINQ कर रहे हैं विशेष रूप से अगर, जहां वे पूरी तरह आवश्यक हो - लेकिन मैं काफी यह एक को समझ नहीं सकता:सी # ऑब्जेक्ट initializers के नेस्टेड उपयोग

public class Class1 { 
    public Class2 instance; 
} 

public class Class2 { 
    public Class1 parent; 
} 

इस तरह का उपयोग कर:

Class1 class1 = new Class1(); 
class1.instance = new Class2(); 
class1.parent = class1; 

एक प्रारंभकर्ता के रूप में:

Class1 class1 = new Class1() { 
    instance = new Class2() { 
     parent = class1 
    } 
}; 

यह काम नहीं करता, Class1 माना जाता है एक असाइन किए गए स्थानीय चर। जब आप

select new Class1() { ... 

की तरह कुछ कर रहे हैं यह Linq में भी जटिल हो जाता है तो यह और भी द्वारा यह उल्लेख करने के लिए एक नाम नहीं है!

मैं इसके आसपास कैसे हो सकता हूं? क्या मैं ऑब्जेक्ट प्रारंभकर्ताओं का उपयोग करके नेस्टेड संदर्भ नहीं बना सकता?

उत्तर

6

मैं बस नेस्टेड संदर्भ वस्तु initializers का उपयोग कर नहीं कर सकता है?

आप सही हैं - आप नहीं कर सकते। एक चक्र होगा; ए को प्रारंभिकरण के लिए बी की आवश्यकता है लेकिन बी को पहले ए की आवश्यकता है। सटीक होने के लिए - आप निश्चित रूप से नेस्टेड ऑब्जेक्ट प्रारंभकर्ता बना सकते हैं लेकिन सर्कुलर निर्भरताओं के साथ नहीं।

लेकिन आप कर सकते हैं - और मैं सुझाव दूंगा कि आपको संभव हो तो - यह इस प्रकार काम करें।

public class A 
{ 
    public B Child 
    { 
     get { return this.child; } 
     set 
     { 
     if (this.child != value) 
     { 
      this.child = value; 
      this.child.Parent = this; 
     } 
     } 
    } 
    private B child = null; 
} 

public class B 
{ 
    public A Parent 
    { 
     get { return this.parent; } 
     set 
     { 
     if (this.parent != value) 
     { 
      this.parent = value; 
      this.parent.Child = this; 
     } 
     } 
    } 
    private A parent = null; 
} 

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

b.Parent = a; 
a.Child = b; 

गुणों में तर्क के साथ आप केवल एक ही कथन के साथ काम करते हैं।

a.Child = b; 

या दूसरी तरफ दौर।

b.Parent = a; 

और अंत में ऑब्जेक्ट प्रारंभकर्ता वाक्यविन्यास के साथ।

A a = new A { Child = new B() }; 
+0

मैं इस सवाल का जवाब चाहते सबसे अच्छा है, लेकिन यह मेरे लिए काम नहीं करता है, क्योंकि मैं बाहर छोड़ दिया है कि Class2 वास्तव में सूची है, उदाहरण स्पष्ट करने के। ड्रैट, यह पीछे हट गया। –

1

यह समस्या प्रारंभकर्ताओं को ऑब्जेक्ट करने के लिए विशिष्ट नहीं है, यह सी # भाषा में एक सामान्य प्रतिबंध है। आप स्थानीय चर का उपयोग तब तक नहीं कर सकते जब तक कि इसे निश्चित रूप से असाइन नहीं किया जाता है। यहाँ एक सरल रेप्रो

Class1 Foo(Class1 c1) { 
    return c1; 
} 

void Example() { 
    Class1 c1 = Foo(c1); 
} 
1

मुझे नहीं लगता कि वैसे भी है इस के आसपास पाने के लिए करते हैं, जब आवेदन Class1 वस्तु instantiating है यह पहली बार Class2 वस्तु बनाया है, ताकि वह जानता है, जहां स्मृति में संदर्भ स्थित है की जरूरत है। आप यह देख सकते हैं यदि आप निम्न प्रयास करें:

 Class1 myClass1 = null; 

     myClass1 = new Class1() 
     { 
      instance = new Class2 
      { 
       parent = myClass1 
      } 
     }; 

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

0

आप निश्चित रूप से नेस्टेड ऑब्जेक्ट प्रारंभकर्ताओं का उपयोग कर सकते हैं, मैं इसे हर समय करता हूं।

हालांकि, आपके विशेष मामले में, आपके ऑब्जेक्ट्स में गोलाकार संदर्भ होता है। आपको इसे दूसरे को सौंपने से पहले तुरंत चालू करना होगा। अन्यथा, आप कंपाइलर को क्लासिक chicken and egg problem सौंप रहे हैं जो इसे संभाल नहीं सकता है।

+0

यह चिकन और अंडे की समस्या नहीं है, कम से कम नहीं कि मैं प्रारंभकर्ताओं को कैसे समझता हूं: ऑब्जेक्ट घोषित करने और इसकी गुणधर्मों को सेट करने के लिए केवल वाक्य रचनात्मक चीनी। –

+0

ठीक है, आपकी "असाइन की गई स्थानीय चर" त्रुटि मुझे अन्यथा बताती है ... –

+0

क्षमा करें - यह ऑब्जेक्ट प्रारंभकर्ताओं को कैसे समझाया गया है इसके अनुसार "यह नहीं होना चाहिए"। पहली वस्तु बनाई गई है, और उसके बाद इसके पैरामीटर मान दिए गए हैं। चूंकि मैं इस शैली में ऐसा कर सकता हूं कि ऑब्जेक्ट इनिटियालाइज़र अनुमानित रूप से संकलित हो जाते हैं, इसलिए मुझे ऑब्जेक्ट प्रारंभकर्ताओं के साथ ऐसा करने में सक्षम होना चाहिए। –

2

आप ऑब्जेक्ट इनलाइज़र के साथ ऐसा नहीं कर सकते हैं। यह कॉलिंग

class A 
{ 
    B b; 

    public B B 
    { 
     set 
     { 
      b = value; 
      b.a = this; 
     } 
     get 
     { 
      return b; 
     } 
    } 
} 

class B 
{ 
    public A a; 
} 

: लेकिन, आप चाल प्रॉपर्टी कोड का उपयोग कर सकते हैं

var a = new A { B = new B() }; 
0

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

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

उदाहरण के लिए

:

public class ParentClass 
{ 
    public List<ChildClass> Children; 
    public void AddChild(ChildClass child) 
    { 
     Children.Add(child); 
     // or something else, etc. 
    } 
    // various stuff like making sure Children actually exists before AddChild is called 
} 

public class ChildClass 
{ 
    public ParentClass Parent; 
    public ChildClass(ParentClass parent) 
    { 
     Parent = parent; 
     Parent.AddChild(this); 
    } 
} 

फिर, अपने बुला कोड में:

var parent = new ChildClass(new ParentClass()).Parent; 

और, हाँ, कि LINQ में काम करता है:

// qry, etc. 
select new ChildClass(new ParentClass()).Parent 

लेकिन फिर कैसे क्या मैं सभी चाइल्ड क्लास बना देता हूं वही ParentClass उदाहरण? - एंडी होहोरस्ट

तब आपको पहले से ही मूल वर्ग को अवश्य पता होना चाहिए।

var parent = new ParentClass(); 
var child = new ChildClass(parent); 

या

var parent = new ParentClass(); 
// qry, etc. 
select new ChildClass(parent) 
+0

लेकिन फिर मैं सभी चाइल्ड क्लास के समान पेरेंट क्लास उदाहरण कैसे बना सकता हूं? –

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