2012-10-31 17 views
59
class Person 
{ 
    public int age; 
    public Person() 
    { 
     age = 1; 
    } 
} 

class Customer : Person 
{ 
    public Customer() 
    { 
     age += 1; 
    } 
} 

Customer customer = new Customer(); 

क्या ग्राहक की उम्र 2 होगी? ऐसा लगता है कि बेस क्लास के कन्स्ट्रक्टर को कोई फर्क नहीं पड़ता। यदि हां, तो हमें कभी-कभी अंत में base पर कॉल करने की आवश्यकता क्यों है?क्या बेस क्लास कन्स्ट्रक्टर स्वचालित रूप से कॉल किया जाएगा?

public Customer() : base() 
{ 
    ............. 
} 
+5

तकनीकी रूप से, 'आयु' एक निजी सदस्य है, जो संकलित नहीं होगा। काम करने के लिए इसे 'सार्वजनिक' होना चाहिए। –

+0

क्षमा करें, मुझे इसका एहसास नहीं हुआ। लेकिन यह सिर्फ मेरे प्रश्न को स्पष्ट करने के लिए है। –

+5

यदि आप नॉन-स्टेटिक कन्स्ट्रक्टर के लिए न तो 'बेस (...)' और न ही ': यह (...)' निर्दिष्ट करते हैं, तो डिफ़ॉल्ट 'बेस() 'i.e. शून्य-पैरामीटर बेस-क्लास कन्स्ट्रक्टर है। आपके पास पहले वर्ग 'व्यक्ति' के साथ भी है जहां आपका 'व्यक्ति() 'कन्स्ट्रक्टर स्पष्ट रूप से' ऑब्जेक्ट() 'बेस क्लास कन्स्ट्रक्टर को कॉल करता है। लेखन ': आधार() '(शून्य तर्क) हमेशा अनावश्यक है। अपने उदाहरण को फिर से प्रयास करें जहां 'व्यक्ति' वर्ग निर्माता एक या अधिक पैरामीटर लेता है। –

उत्तर

51

यह बस सी # काम करने जा रहा है। टाइप पदानुक्रम में प्रत्येक प्रकार के कन्स्ट्रक्टर को अधिकांश बेस -> सर्वाधिक व्युत्पन्न के क्रम में बुलाया जाएगा।

तो आपके विशेष उदाहरण में, यह Person() पर कॉल करता है, और उसके बाद Customer() कन्स्ट्रक्टर ऑर्डर में कॉल करता है। कभी-कभी base कन्स्ट्रक्टर का उपयोग करने की आवश्यकता का कारण यह है कि वर्तमान प्रकार के नीचे के रचनाकारों को अतिरिक्त पैरामीटर की आवश्यकता होती है। उदाहरण के लिए:

public class Base 
{ 
    public int SomeNumber { get; set; } 

    public Base(int someNumber) 
    { 
     SomeNumber = someNumber; 
    } 
} 

public class AlwaysThreeDerived : Base 
{ 
    public AlwaysThreeDerived() 
     : base(3) 
    { 
    } 
} 

आदेश में एक AlwaysThreeDerived वस्तु का निर्माण करने में, यह एक parameterless निर्माता है। हालांकि, Base प्रकार नहीं है। इसलिए एक पैरामीटर रहित कन्स्ट्रक्टर बनाने के लिए, आपको बेस कंसक्टर को एक तर्क प्रदान करने की आवश्यकता है, जिसे आप base कार्यान्वयन के साथ कर सकते हैं।

+0

आप जो कहते हैं वह सत्य है। हालांकि, आधार को पैरामीटरयुक्त कन्स्ट्रक्टर के अलावा पैरामीटर रहित कन्स्ट्रक्टर होने से रोकने के लिए कुछ भी नहीं है जो कुछ यादृच्छिक संख्या को कहने के लिए सेट करें। AlwaysThreeDerived अभी भी बेस (3) कॉल का उपयोग करेगा, लेकिन एक और वर्ग (इसे RandomDerived कहते हैं) उस पैरामीटर रहित बेस कन्स्ट्रक्टर को निर्दिष्ट किए बिना आधार से प्राप्त कर सकता है। –

+0

सही - मैं बेस कन्स्ट्रक्टर को स्पष्ट रूप से आमंत्रित करने के लिए अक्सर उपयोग किए जाने वाले कारणों पर एक त्वरित उदाहरण दे रहा था। – Tejs

+0

सहमत (और +1)। बस स्वयं घोषित नौसिखिया से छिपाना नहीं चाहता था। :) –

37

हां, बेस क्लास कन्स्ट्रक्टर स्वचालित रूप से कॉल किया जाएगा। कोई तर्क के साथ कोई कन्स्ट्रक्टर होने पर आपको base() पर एक स्पष्ट कॉल जोड़ने की आवश्यकता नहीं है।

निर्माण के बाद ग्राहक की उम्र को प्रिंट करके आप आसानी से इसका परीक्षण कर सकते हैं (link to ideone with a demo)।

9

आप एक डिफ़ॉल्ट parameterless निर्माता नहीं था, तो फिर वहाँ मानकों के साथ एक कॉल करने के लिए एक की जरूरत होगी:

class Person 
{ 
    public Person(string random) 
    { 

    } 
} 

class Customer : Person 
{ 
    public Customer(string random) : base (random) 
    { 

    } 
} 
+1

हाँ, यही वह है जिसे मैं ढूंढ रहा था, धन्यवाद। – DrNachtschatten

0

मैं जोड़ने के लिए कुछ ख़ास नहीं है, लेकिन मैं ने पाया है कि मैं करने की जरूरत है MyConstructor(): आधार() को 1 मामले में कोई पैराम के साथ कॉल करें। मेरे पास एक बेस क्लास है जो INotifyProperty को लागू करता है जिस तरह से मेरे पास एक रजिस्टरप्रॉपर्टीज() वर्चुअल फ़ंक्शन है। जब मैं इसे ओवरराइड करता हूं, इसे बेस कन्स्ट्रक्टर में बुलाया जाता है। इसलिए मैं इसे हाल ही में व्युत्पन्न उप-वर्गों में कॉल करने के लिए समाप्त कर रहा हूं क्योंकि ओवरराइड वर्चुअल को पहचानने से पहले बेस को स्पष्ट रूप से बुलाया गया था। मेरे गुण तब तक सूचित नहीं करते जब तक कि मैं ऐसा नहीं करता। संपूर्ण आधार वर्ग नीचे है।

मैंने सीधे नीचे डेटाबेस डाटाबेस उपclass जोड़ा। खाली आधार() कॉल के बिना, मेरी संपत्ति OnPropertyChanged() को कॉल नहीं करती है।

[DataContract] 
public abstract class DataModelBase : INotifyPropertyChanged, IDataErrorInfo { 

    #region Properties 

    [IgnoreDataMember] 
    public object Self { 
     get { return this; } 
     //only here to trigger change 
     set { OnPropertyChanged("Self"); } 
    } 

    #endregion Properties 

    #region Members 

    [IgnoreDataMember] 
    public Dispatcher Dispatcher { get; set; } 

    [DataMember] 
    private Dictionary<object, string> _properties = new Dictionary<object, string>(); 

    #endregion Members 

    #region Initialization 

    public DataModelBase() { 
     if(Application.Current != null) Dispatcher = Application.Current.Dispatcher; 
     _properties.Clear(); 
     RegisterProperties(); 
    } 

    #endregion Initialization 

    #region Abstract Methods 

    /// <summary> 
    /// This method must be defined 
    /// </summar 
    protected abstract void RegisterProperties(); 

    #endregion Abstract Methods 

    #region Behavior 

    protected virtual void OnPropertyChanged(string propertyName) { 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 
    } 

    protected bool RegisterProperty<T>(ref T property, string propertyName) { 
     //causes problems in design mode 
     //if (property == null) throw new Exception("DataModelBase.RegisterProperty<T> : ref T property cannot be null."); 
     if (_properties.ContainsKey(property)) return false; 

     _properties.Add(property, propertyName); 

     return true; 
    } 

    protected string GetPropertyName<T>(ref T property) { 
     if (_properties.ContainsKey(property)) 
      return _properties[property]; 

     return string.Empty; 
    } 

    protected bool SetProperty<T>(ref T property, T value) { 
     //if (EqualityComparer<T>.Default.Equals(property, value)) return false; 
     property = value; 
     OnPropertyChanged(GetPropertyName(ref property)); 
     OnPropertyChanged("Self"); 

     return true; 
    } 

    [OnDeserialized] 
    public void AfterSerialization(StreamingContext context) { 
     if (Application.Current != null) Dispatcher = Application.Current.Dispatcher; 
     //---for some reason this member is not allocated after serialization 
     if (_properties == null) _properties = new Dictionary<object, string>(); 
     _properties.Clear(); 
     RegisterProperties(); 
    } 

    #endregion Behavior 

    #region INotifyPropertyChanged Members 

    public event PropertyChangedEventHandler PropertyChanged; 

    #endregion INotifyPropertyChanged Members 

    #region IDataErrorInfo Members 

    string IDataErrorInfo.Error { 
     get { throw new NotImplementedException(); } 
    } 

    string IDataErrorInfo.this[string propertyName] { 
     get { throw new NotImplementedException(); } 
    } 

    #endregion IDataErrorInfo Members 

} //End class DataModelBaseclass DataModelBase 

/*I decided to add an example subclass*/ 
    [DataContract] 
public abstract class DatabaseTraits : DataModelBase { 
    #region Properties 
    private long _id = -1; 
    [DataMember] 
    public long Id { 
     get { return _id; } 
     set { SetProperty(ref _id, value); } 
    } 
    private bool _isLocked = false; 
    [DataMember] 
    public bool IsLocked { 
     get { return _isLocked; } 
     set { SetProperty(ref _isLocked, value); } 
    } 

    private string _lockedBy = string.Empty; 
    [DataMember] 
    public string LockedBy { 
     get { return _lockedBy; } 
     set { SetProperty(ref _lockedBy, value); } 
    } 

    private DateTime _lockDate = new DateTime(0); 
    [DataMember] 
    public DateTime LockDate { 
     get { return _lockDate; } 
     set { SetProperty(ref _lockDate, value); } 
    } 

    private bool _isDeleted = false; 
    [DataMember] 
    public bool IsDeleted { 
     get { return _isDeleted; } 
     set { SetProperty(ref _isDeleted, value); } 
    } 
    #endregion Properties 

    #region Initialization 
    public DatabaseTraits() : base() { 
     /*makes sure my overriden RegisterProperties() is called.*/ 
    } 
    protected override void RegisterProperties() { 
     RegisterProperty(ref _id, "Id"); 
     RegisterProperty(ref _isLocked, "IsLocked"); 
     RegisterProperty(ref _lockedBy, "LockedBy"); 
     RegisterProperty(ref _lockDate, "LockDate"); 
     RegisterProperty(ref _isDeleted, "IsDeleted"); 
    } 
    #endregion Initialization 

    #region Methods 
    public void Copy(DatabaseTraits that) { 
     Id = that.Id; 
     IsLocked = that.IsLocked; 
     LockedBy = that.LockedBy; 
     LockDate = that.LockDate; 
     IsDeleted = that.IsDeleted; 
    } 
    #endregion Methods 
} 
0

सी # में आधार का उपयोग करने और व्युत्पन्न वर्ग वहां व्युत्पन्न वर्ग से आधार वर्ग में कुछ निर्माता को कुछ अस्पष्ट या स्पष्ट कॉल हो जाना चाहिए।

मुझे समझ में नहीं आया कि जब तक मैंने यह तथ्य महसूस नहीं किया तब तक यह सब कैसे काम करता था।

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

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

आइए परीक्षण इस .....

// THIS WORKS!!! 
class MyBaseClass0 
{ 
    // no default constructor - created automatically for you 
} 
class DerivedClass0 : MyBaseClass0 
{ 
    // no default constructor - created automatically for you and calls the base class default constructor above 
} 

// THIS WORKS!!! 
class MyBaseClass1 
{ 
    // same as above 
} 
class DerivedClass1 : MyBaseClass1 
{ 
    public DerivedClass1() 
    { 
     // here the derived class default constructor is created explicitly but the call to the base class default constructor is implicitly called 
    } 
} 

// AND THIS WORKS!!! 
class MyBaseClass2 
{ 
    // as above 
} 
class DerivedClass2 : MyBaseClass2 
{ 
    public DerivedClass2() : base() 
    { 
     // here we explicitly call the default constructor in the base class using base(). note its optional as base constructor would be called anyway here 
    } 
} 

// AND THIS WORKS!!! 
class MyBaseClass3 
{ 
    // no default constructor 
} 
class DerivedClass3 : MyBaseClass3 
{ 
    public DerivedClass3(int x)//non-default constructor 
    { 
     // as above, the default constructor in the base class is called behind the scenes implicitly here 
    } 
} 

// AND THIS WORKS 
class MyBaseClass4 
{ 
    // non default constructor but missing default constructor 
    public MyBaseClass4(string y) 
    { 

    } 
} 
class DerivedClass4 : MyBaseClass4 
{ 
    // non default constructor but missing default constructor 
    public DerivedClass4(int x) : base("hello") 
    { 
     // note that here, we have fulfilled the requirement that some constructor be called in base even if its not default 
    } 
} 

// BUT THIS FAILS!!!...until you either add in a base() call to the non-default constructor or add in the default constructor into base! 
class MyBaseClass5 
{ 
    // 1. EITHER ADD MISSING DEFAULT CONSTRUCTOR HERE AND CALL IT USING base() below.... 
    public MyBaseClass5() { } 

    // 2. Or use the non-default constructor and call to base("hello") below 
    //public MyBaseClass5(string y) 
    //{ 
    //} 
} 
class DerivedClass5 : MyBaseClass5 
{ 
    public DerivedClass5(int x) : base()// 1. Either ADD explicit call here to explicit default constructor in base class 
    { 
    } 

    //public DerivedClass5(int x) : base("hello")// 2. Or ADD explicit call here to parameter-based constructor in base class 
    //{ 
    //} 
} 

कारण काम से ऊपर सभी आइटम है या तो: 1. आधार वर्ग में डिफ़ॉल्ट निर्माता को कॉल परोक्ष आधार वर्ग में बनाई गई है और परोक्ष से ली गई है क्योंकि कोई गैर-डिफ़ॉल्ट निर्माता आधार वर्ग में जोड़ा गया है या 2. एक स्पष्ट गैर-डिफ़ॉल्ट, पैरामीटर के आधार पर निर्माता के लिए (myparamter)

  • आधार का उपयोग कर कॉल नहीं है क्या भ्रमित कर रहा है कहा जाता है कब और क्यों def अल्ट कन्स्ट्रक्टर बेस क्लास में बनाए जाते हैं और व्युत्पन्न कक्षाओं से बुलाए जाते हैं। यह तब होता है जब आधार में कोई गैर-डिफ़ॉल्ट कन्स्ट्रक्टर दिखाई देता है।
संबंधित मुद्दे