2011-08-18 24 views
5

कन्स्ट्रक्टर को शीर्ष से नीचे आईई क्रम में निष्पादित करने से पहले व्युत्पन्न वर्ग के फ़ील्ड प्रारंभकर्ता क्यों निष्पादित किए जाते हैं। आधार का पहला व्युत्पन्न एक के बाद। यह विवाद एक महत्वपूर्ण ओओपी आश्वासन पर आधारित है कि इसका उपयोग करने से पहले एक वस्तु (आधार यहां) को हमेशा प्रारंभ किया जाना चाहिए (यहां व्युत्पन्न वर्ग के कन्स्ट्रक्टर में)।बेस क्लास के शुरुआती

मुझे आश्चर्य है कि क्यों फील्ड-प्रारंभकर्ता सी # में इस सिद्धांत का पालन नहीं करते हैं? क्या मुझसे कोई चूक हो रही है?

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

public class ForumController : AppControllerBase 
{ 
     ForumRepository repository = new ForumRepository(Identity); 
    // Above won't compile since Identity is in the base class. 

    // ... Action methods. 
} 

अब मैं केवल एक ही विकल्प केवल के लिए एक डिफ़ॉल्ट निर्माता के साथ अपने हर नियंत्रक मोटा करने के पहचान के साथ भंडार वस्तु के आरंभ का काम करने के लिए है कि के साथ छोड़ दिया हूँ।

+0

नहीं, इसका कारण यह संकलित नहीं करता है कि आधार वर्ग में 'पहचान' है, यह केवल इसलिए है क्योंकि यह एक उदाहरण सदस्य है। तो, शीर्षक में प्रश्न जो आप करने की कोशिश कर रहे हैं उससे प्रासंगिक नहीं है ... – Guffa

उत्तर

6

क्यों एक व्युत्पन्न वर्ग के क्षेत्र initializers से पहले आधार वर्ग क्षेत्र initializers क्रियान्वित कर रहे हैं?

अच्छा सवाल। मैं 2008 से इन ब्लॉग पोस्ट में अपने प्रश्न का उत्तर:

 
    Perform all field initializers 
    Chain to base class constructor 
    Execute user-supplied code for constructor 

vb.net में, अनुक्रम है:

http://blogs.msdn.com/b/ericlippert/archive/2008/02/15/why-do-initializers-run-in-the-opposite-order-as-constructors-part-one.aspx

http://blogs.msdn.com/b/ericlippert/archive/2008/02/18/why-do-initializers-run-in-the-opposite-order-as-constructors-part-two.aspx

0

फील्ड प्रारंभिक निर्माता को कन्स्ट्रक्टर में निष्पादित किया जाता है, और बेस क्लास में कन्स्ट्रक्टर को पहले कहा जाता है, इसलिए सभी फ़ील्ड प्रारंभकर्ताओं को व्युत्पन्न कन्स्ट्रक्टर निष्पादन से पहले निष्पादित किया जाता है।

उदाहरण:

public class Base { 

    // field initialiser: 
    private string _firstName = "Arthur"; 

    public string FirstName { get { return _firstName;}} 
    public string LastName { get; private set; } 

    // initialiser in base constructor:  
    public Base() { 
    LastName = "Dent"; 
    } 

} 

public class Derived : Base { 

    public string FirstNameCopy { get; private set; } 
    public string LastNameCopy { get; private set; } 

    public Derived() { 
    // get values from base class: 
    FirstNameCopy = FirstName; 
    LastNameCopy = LastName; 
    } 

} 

टेस्ट:

Derived x = new Derived(); 
Console.WriteLine(x.FirstNameCopy); 
Console.WriteLine(x.LastNameCopy); 

आउटपुट:

Arthur 
Dent 
+0

मुझे लगता है कि आपको मेरा अंक नहीं मिला। मैं पहले से ही जानता हूं कि आप क्या कह रहे हैं।मेरा सवाल यह है कि आधार और व्युत्पन्न दोनों वर्गों में फ़ील्ड-प्रारंभकर्ताओं को दिया गया है, क्यों व्युत्पन्न वर्ग का पहला और फिर मूल आधार पर निष्पादित किया जाता है? यदि आप रचनाकार देखते हैं तो यह बिल्कुल विपरीत है। –

+0

@ वरुण के: मैं देखता हूं, आप किसी फील्ड प्रारंभकर्ता से किसी फ़ील्ड तक पहुंचने का प्रयास कर रहे हैं। आप ऐसा नहीं कर सकते, क्योंकि आप प्रारंभिक सदस्यों से इंस्टेंस सदस्यों का उपयोग नहीं कर सकते हैं, और इसका अलग-अलग वर्गों में होने वाले फ़ील्ड से कोई लेना देना नहीं है। – Guffa

+0

मुझे पता है कि मैं ऐसा नहीं कर सकता :-)। लेकिन मैं इसके पीछे कारण जानना चाहता था। –

0

फील्ड initializers निर्माताओं के लिए एक स्थानापन्न के होने के लिए नहीं होती हैं।

एमएसडीएन दस्तावेज के अनुसार सभी फील्ड प्रारंभकर्ता कन्स्ट्रक्टर से पहले निष्पादित किए जाते हैं। हालांकि फील्ड इनिशिलाइज़र पर एक प्रतिबंध यह है कि वे अन्य इंस्टेंस फ़ील्ड का उल्लेख नहीं कर सकते हैं। (http://msdn.microsoft.com/en-us/library/ms173118(v=vs.80).aspx)

प्रतिबंध इस तथ्य के कारण है कि सही क्रम की पहचान करने के लिए कोई तरीका नहीं है और संकलक स्तर पर फील्ड प्रारंभकर्ताओं को निष्पादित करने के लिए निर्भरता नहीं है।

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


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

जहां तक ​​एक व्युत्पन्न वर्ग का संबंध है, आधार वर्ग क्षेत्रों में एक ही है कि क्या वे प्रारंभकर्ता या निर्माता के माध्यम से प्रारंभ कर रहे हैं देखो। यह जानकारी बाल कक्षाओं को नहीं दी जा सकती है क्योंकि इसका मतलब आधार वर्ग के कार्यान्वयन को उजागर करना है (जो आधार वर्ग के लिए सख्ती से निजी है)।

इसका तात्पर्य है कि व्युत्पन्न कक्षा प्रारंभकर्ता को यह पता लगाने का कोई तरीका नहीं है कि सभी बेस क्लास फ़ील्ड उन्हें एक्सेस करने से पहले प्रारंभ किए गए हैं या नहीं। इसलिए व्यवहार की अनुमति नहीं है।

+0

मुझे पहले से ही इस प्रतिबंध बिंदु (सही क्रम और निर्भरता) पता है, लेकिन यदि आप देखते हैं, तो यह एक ही कक्षा के क्षेत्रों में सख्ती से लागू होता है। मैं व्युत्पन्न वर्ग में आधार बनाम क्षेत्र-प्रारंभकर्ता में फ़ील्ड-प्रारंभकर्ताओं के संदर्भ में पूछताछ कर रहा हूं –

2

सी # में, एक निर्माता अनुक्रम चलाता है:

 
    Chain to base class constructor 
    Perform all field initializers 
    Execute user-supplied code for constructor 

कोई फ्रेमवर्क-बेस नहीं है एड कारण क्यों सी # चीजों को क्रम में करता है, जैसा कि यह करता है कि vb.net उन्हें एक अलग अनुक्रम में कर सकता है और करता है। सी # दृष्टिकोण के लिए डिज़ाइन औचित्य यह है कि सभी फ़ील्ड प्रारंभकर्ताओं (व्युत्पन्न- साथ ही बेस-क्लास फ़ील्ड्स के लिए) चलाने से पहले बाहरी दुनिया में किसी वस्तु को उजागर करने की कोई संभावना नहीं होनी चाहिए; चूंकि बेस-क्लास कन्स्ट्रक्टर किसी ऑब्जेक्ट को बाहरी दुनिया में उजागर कर सकता है, इसलिए उस आवश्यकता को लागू करने का मतलब है कि फ़ील्ड प्रारंभकर्ता को बेस-क्लास कन्स्ट्रक्टर से पहले चलाना चाहिए।

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

संयोग से, एक विशेषता जिसे मैं दोनों vb.net और सी # में देखना चाहता हूं, पैरामीटर-प्रारंभिक फ़ील्ड और छद्म-फ़ील्ड घोषित करने का माध्यम होगा। यदि किसी वर्ग में एक निश्चित नाम और प्रकार का पैरामीटर-प्रारंभिक फ़ील्ड होता है, तो उस वर्ग के प्रत्येक कन्स्ट्रक्टर जो एक ही कक्षा के किसी अन्य श्रृंखला में नहीं है, उचित नामों और प्रकारों के साथ पैरामीटर होना चाहिए। उन क्षेत्रों के मूल्यों को कन्स्ट्रक्टर में सेट किया जाएगा इससे पहले कि कुछ और किया जाता है, और अन्य फील्ड प्रारंभकर्ताओं के लिए सुलभ होगा। छद्म-क्षेत्र क्षेत्रीय रूप से क्षेत्रों की तरह व्यवहार करेंगे, सिवाय इसके कि वे केवल फ़ील्ड प्रारंभकर्ताओं के भीतर प्रयोग योग्य होंगे, और इसे कन्स्ट्रक्टर के भीतर स्थानीय चर के रूप में लागू किया जाएगा। ऐसी सुविधा कई प्रकार की संरचनाओं को अधिक सुविधाजनक बनाती है। उदाहरण के लिए, अपने जीवन भर एक विशेष सरणी उदाहरण धारण करने के लिए करता है, तो एक प्रकार माना जाता है, कहने के लिए सक्षम किया जा रहा:

 
    readonly param int Length; 
    readonly ThingType[] myArray = new ThingType[Length]; 

या तो वर्ग निर्माता में सरणी के निर्माण के लिए की तुलना में अच्छे प्रतीत होता है (जो ऐसा नहीं कर सकता बेस कन्स्ट्रक्टर के चलने के बाद तक) (या vb.net के लिए) को बेस-क्लास कन्स्ट्रक्टर तक लम्बाई पास करनी होती है जो तब इसे एक फ़ील्ड सेट करने के लिए उपयोग कर सकती है (जो क्लास में स्पेस पर कब्जा कर लेती है, भले ही उसका मूल्य - Length ऊपर की तरह - अनावश्यक हो सकता है)।

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