2009-11-29 8 views
182

मुझे पता है कि यह माना जाता है कि एक सुपर सरल सवाल है, लेकिन मैं कुछ समय के लिए अवधारणा के साथ अब संघर्ष कर रहा है। मेरा सवाल है, आप सी # में चेन कन्स्ट्रक्टर कैसे करते हैं? मैं अपनी पहली ओओपी कक्षा में हूं, इसलिए मैं बस सीख रहा हूं। मुझे समझ में नहीं आता कि कैसे कन्स्ट्रक्टर चेनिंग काम करता है या इसे कैसे कार्यान्वित किया जाता है, या यहां तक ​​कि चेनिंग के बिना कन्स्ट्रक्टर करने से बेहतर क्यों है।सी # कन्स्ट्रक्टर चेनिंग? (यह करने के लिए कैसे?)

मैं स्पष्टीकरण के साथ कुछ उदाहरणों की सराहना करता हूं।

तो उन्हें कैसे श्रृंखलाबद्ध करें? मुझे पता है कि यह दो है:

public SomeClass this: {0} 

public SomeClass 
{ 
    someVariable = 0 
} 

लेकिन आप इसे तीन, चार और इतने पर कैसे करते हैं?

फिर से, मैं जानता हूँ कि यह अभी शुरुआत सवाल है, लेकिन मैं इस बात को समझ के लिए संघर्ष कर रहा हूं और मुझे पता नहीं क्यों।

उत्तर

275

आप मानक वाक्य रचना (एक विधि की तरह this का प्रयोग करके) का उपयोग अधिभार, वर्ग अंदर लेने के लिए:

class Foo { 
    private int id; 
    private string name; 
    public Foo() : this(0, "") { 
    } 
    public Foo(int id, string name) { 
     this.id = id; 
     this.name = name; 
    } 
    public Foo(int id) : this(id, "") { 
    } 
    public Foo(string name) : this(0, name) { 
    } 
} 

तो:

Foo a = new Foo(), b = new Foo(456,"def"), c = new Foo(123), d = new Foo("abc"); 

यह भी ध्यान रखें:

  • आपका उपयोग कर बेस-टाइप पर कन्स्ट्रक्टर को चेन कर सकते हैं
  • आप
  • डिफ़ॉल्ट प्रत्येक निर्माता में अतिरिक्त कोड डाल सकते हैं (आप कुछ भी उल्लेख नहीं करते हैं, तो) base()

है "क्यों?":

  • कोड में कमी (हमेशा एक अच्छी बात)
  • आवश्यक गैर-डिफ़ॉल्ट बेस-कंस्ट्रक्टर को कॉल करने के लिए, उदाहरण के लिए:

    SomeBaseType(int id) : base(id) {...} 
    

ध्यान दें कि आप भी वस्तु initializers एक समान तरीके से, हालांकि (कुछ भी लिखने के लिए जरूरत के बिना) का उपयोग कर सकते हैं:

SomeType x = new SomeType(), y = new SomeType { Key = "abc" }, 
     z = new SomeType { DoB = DateTime.Today }; 
+0

मैं कुछ श्रृंखलन कर रहा हूँ और एक सवाल पूछने की के बाद से इस सवाल का जवाब इतना उच्च स्थान पर चुना गया है। क्या प्रत्येक कन्स्ट्रक्टर को पास किए गए गुणों को सेट करने के लिए कोई नुकसान है, और फिर दूसरों को सेट करने के लिए डिफ़ॉल्ट कन्स्ट्रक्टर को कॉल करें? इस तरह आप एक से अधिक स्थानों (त्रुटि के लिए कम मौका) में डिफ़ॉल्ट मान ('0' और' "" ') को कोडिंग नहीं कर रहे हैं। उदाहरण के लिए: 'सार्वजनिक फू (int आईडी): यह() {this.id = id; } '? वैकल्पिक रूप से, मैं यह भी विचार कर रहा था: 'सार्वजनिक फू (int आईडी): यह ("") {this.id = id; } '। बस उन्हें चेन करने के लिए सबसे अच्छा तार्किक तरीका तलाश रहे हैं, किसी भी विचार की सराहना करते हैं। –

+0

क्या अन्य जंजीर कन्स्ट्रक्टर कहने से पहले पहले कन्स्ट्रक्टर में कन्स्ट्रक्टर कहलाए जाने के तर्क मानों में हेरफेर करने का कोई तरीका है? – eaglei22

5

आप इस के बारे में पूछ रहे हैं?

public class VariantDate { 
    public int day; 
    public int month; 
    public int year; 

    public VariantDate(int day) : this(day, 1) {} 

    public VariantDate(int day, int month) : this(day, month,1900){} 

    public VariantDate(int day, int month, int year){ 
    this.day=day; 
    this.month=month; 
    this.year=year; 
    } 

} 
25

यह एक उदाहरण के साथ सबसे अच्छा चित्रित है। इमेजिंग हम एक वर्ग व्यक्ति

public Person(string name) : this(name, string.Empty) 
{ 
} 

public Person(string name, string address) : this(name, address, string.Empty) 
{ 
} 

public Person(string name, string address, string postcode) 
{ 
    this.Name = name; 
    this.Address = address; 
    this.Postcode = postcode; 
} 

तो यहाँ हम एक निर्माता जो कुछ गुण सेट करता है, और तुम सिर्फ एक नाम, या सिर्फ एक नाम और पता के साथ वस्तु बनाने के लिए अनुमति देने के लिए चेनिंग निर्माता का उपयोग करता है है। तुम सिर्फ एक नाम के साथ एक उदाहरण बनाते हैं इस नाम और पते, जो तब अंतिम निर्माता के माध्यम से पोस्टकोड लिए एक डिफ़ॉल्ट मान भेजता है के माध्यम से एक डिफ़ॉल्ट मान, string.Empty भेज देंगे।

ऐसा करने में आप कोड की राशि आपके द्वारा लिखी गई कम करने कर रहे हैं।केवल एक कन्स्ट्रक्टर में वास्तव में कोड होता है, आप स्वयं को दोहराना नहीं चाहते हैं, इसलिए, उदाहरण के लिए, यदि आप किसी संपत्ति से किसी आंतरिक क्षेत्र में नाम बदलते हैं तो आपको केवल एक कन्स्ट्रक्टर को बदलना होगा - यदि आप उस प्रॉपर्टी को तीनों रचनाकारों में सेट करेंगे यह बदलने के लिए तीन जगह होगी।

54

मैं सिर्फ इस के लिए खोज रहे किसी को भी एक वैध बिंदु लाना चाहता हूं। यदि आप 4.0 (वीएस -2010) से पहले .NET संस्करणों के साथ काम करने जा रहे हैं, तो कृपया सलाह दीजिये कि आपको ऊपर दिखाए गए कन्स्ट्रक्टर चेन बनाना होगा।

हालांकि, यदि आप 4.0 में रह रहे हैं, तो मेरे पास अच्छी खबर है। अब आप वैकल्पिक तर्क के साथ एक एकल कन्स्ट्रक्टर कर सकते हैं! मैं फू वर्ग उदाहरण को सरल बना रहे:

class Foo { 
    private int id; 
    private string name; 

    public Foo(int id = 0, string name = "") { 
    this.id = id; 
    this.name = name; 
    } 
} 

class Main() { 
    // Foo Int: 
    Foo myFooOne = new Foo(12); 
    // Foo String: 
    Foo myFooTwo = new Foo(name:"Timothy"); 
    // Foo Both: 
    Foo myFooThree = new Foo(13, name:"Monkey"); 
} 

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

मुझे आशा है कि आप इस सबक का आनंद लेंगे! मैं बस विश्वास नहीं कर सकता कि डेवलपर्स निर्माण श्रृंखला के बारे में शिकायत कर रहे हैं और 2004/2005 के बाद से डिफ़ॉल्ट वैकल्पिक तर्कों का उपयोग करने में सक्षम नहीं हैं! अब यह विकास दुनिया में इतने लंबे समय से लिया गया है, कि डेवलपर्स इसका उपयोग करने से डरते हैं क्योंकि यह पीछे की तरफ संगत नहीं होगा।

+46

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

+1

डिफ़ॉल्ट तर्क दृष्टिकोण के साथ एक और दोष यह है कि यदि आपके पास कन्स्ट्रक्टर में दो डिफ़ॉल्ट तर्क हैं, तो आप इसे केवल दूसरे के साथ कॉल नहीं कर सकते हैं। उदाहरण में, आप के लिए त्रुटि संकलित करना होगा: 'Foo myFooOne = new Foo (""); ' –

9

मैं एक डायरी वर्ग है और इसलिए मैं नहीं लिख रहा हूँ मान सेट फिर से और फिर

public Diary() { 
    this.Like = defaultLike; 
    this.Dislike = defaultDislike; 
} 

public Diary(string title, string diary): this() 
{ 
    this.Title = title; 
    this.DiaryText = diary; 
} 

public Diary(string title, string diary, string category): this(title, diary) { 
    this.Category = category; 
} 

public Diary(int id, string title, string diary, string category) 
    : this(title, diary, category) 
{ 
    this.DiaryID = id; 
} 
2

मैं निम्नलिखित उम्मीद उदाहरण निर्माता श्रृंखलन पर कुछ प्रकाश डाला। उदाहरण के लिए
मेरा उपयोग केस उदाहरण के लिए, आप उपयोगकर्ता को कन्स्ट्रक्टर में निर्देशिका पास करने की उम्मीद कर रहे हैं, उपयोगकर्ता नहीं जानता कि कौन सी निर्देशिका पास होनी है और को डिफ़ॉल्ट निर्देशिका असाइन करने का निर्णय लेता है। आप कदम उठाते हैं और एक डिफ़ॉल्ट निर्देशिका असाइन करते हैं जो आपको लगता है कि काम करेगा।

बीटीडब्ल्यू, मैंने इस उदाहरण के लिए LINQPad का उपयोग किया है यदि आप सोच रहे हैं कि * डंप() क्या है।
चियर्स

void Main() 
{ 

    CtorChaining ctorNoparam = new CtorChaining(); 
    ctorNoparam.Dump(); 
    //Result --> BaseDir C:\Program Files (x86)\Default\ 

    CtorChaining ctorOneparam = new CtorChaining("c:\\customDir"); 
    ctorOneparam.Dump();  
    //Result --> BaseDir c:\customDir 
} 

public class CtorChaining 
{ 
    public string BaseDir; 
    public static string DefaultDir = @"C:\Program Files (x86)\Default\"; 


    public CtorChaining(): this(null) {} 

    public CtorChaining(string baseDir): this(baseDir, DefaultDir){} 

    public CtorChaining(string baseDir, string defaultDir) 
    { 
     //if baseDir == null, this.BaseDir = @"C:\Program Files (x86)\Default\" 
     this.BaseDir = baseDir ?? defaultDir; 
    } 
} 
0

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

उदाहरण के लिए मैं एक बैकिंग चर हो सकता हूं जो मेरे डिफ़ॉल्ट कन्स्ट्रक्टर द्वारा डिफ़ॉल्ट मान पर सेट हो जाता है लेकिन इसमें ओवरराइट होने की क्षमता है।

public class MyClass 
{ 
    private IDependency _myDependency; 
    MyClass(){ _myDependency = new DefaultDependency(); } 
    MYClass(IMyDependency dependency) : this() { 
    _myDependency = dependency; //now our dependency object replaces the defaultDependency 
    } 
} 
1

"कन्स्ट्रक्टर चेन" का उपयोग क्या है?
आप इसे किसी अन्य निर्माता से एक कन्स्ट्रक्टर को कॉल करने के लिए उपयोग करते हैं।

"कन्स्ट्रक्टर चेन" को कैसे कार्यान्वित किया जा सकता है?
कन्स्ट्रक्टर की परिभाषा के बाद ": (आपकी प्रॉपर्टीज)" कीवर्ड का उपयोग करें। उदाहरण के लिए:

Class MyBillClass 
{ 
    private DateTime requestDate; 
    private int requestCount; 

    public MyBillClass() 
    { 
     /// ===== we naming "a" constructor ===== /// 
     requestDate = DateTime.Now; 
    } 
    public MyBillClass(int inputCount) : this() 
    { 
     /// ===== we naming "b" constructor ===== /// 
     /// ===== This method is "Chained Method" ===== /// 
     this.requestCount= inputCount; 
    } 
} 

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

यह कैसे काम करता है? (या, "कन्स्ट्रक्टर चेन" में निष्पादन अनुक्रम क्या है)?
उपरोक्त उदाहरण में, विधि "ए" पहले निष्पादित की जाएगी, और फिर निर्देश अनुक्रम विधि "बी" पर वापस आ जाएगा। दूसरे शब्दों में, ऊपर नीचे दिए गए कोड के साथ बराबर है:

Class MyBillClass 
{ 
    private DateTime requestDate; 
    private int requestCount; 

    public MyBillClass() 
    { 
     /// ===== we naming "a" constructor ===== /// 
     requestDate = DateTime.Now; 
    } 
    public MyBillClass(int inputCount) : this() 
    { 
     /// ===== we naming "b" constructor ===== /// 
     // ===== This method is "Chained Method" ===== /// 

     /// *** --- > Compiler execute "MyBillClass()" first, And then continue instruction sequence from here 
     this.requestCount= inputCount; 
    } 
} 
संबंधित मुद्दे