基类的构造函数会自动调用吗?

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

顾客的年龄是2岁? 好像基类的构造函数会被调用,不pipe是什么。 如果是这样的话,为什么我们有时候最后需要打电话给base呢?

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

这只是C#如何工作。 types层次结构中每个types的构造函数将按照Most Base – > Most Derived的顺序被调用。

所以在你的特定实例中,它调用Person() ,然后在构造函数中调用Customer() 。 有时需要使用base构造函数的原因是,当前types下的构造函数需要额外的参数。 例如:

 public class Base { public int SomeNumber { get; set; } public Base(int someNumber) { SomeNumber = someNumber; } } public class AlwaysThreeDerived : Base { public AlwaysThreeDerived() : base(3) { } } 

为了构造一个AlwaysThreeDerived对象,它有一个无参数的构造函数。 但是, Basetypes不。 所以为了创build一个无参数的构造函数,你需要为基础构造函数提供一个参数,你可以使用base实现来实现。

是的,基类构造函数将被自动调用。 当没有参数的构造函数时,不需要添加对base()的显式调用。

您可以通过在施工后打印出客户的年龄来轻松testing( 通过演示链接到ideone )。

如果你没有默认的无参数构造函数,那么就需要用参数调用它:

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

我没有太多的补充,但我发现我需要在1个情况下调用MyConstructor():base()没有参数。 我有一个基类实现INotifyPropertyChanged的方式,我有一个RegisterProperties()虚拟function。 当我重写它时,它在基础构造函数中被调用。 所以我最后不得不在最近派生的子类中调用它,因为在被覆盖的虚拟被识别之前,基地显然被调用。 我的属性不通知,除非我这样做。 整个基类都在下面。

我在它的正下方添加了一个DatabaseTraits子类。 没有空的base()调用,我的属性不会调用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 } 

在C#中使用基类和派生类必须有一些隐式或显式调用一些构造函数在派生类的基类。

我不明白这一切是如何工作的,直到我意识到这个事实。

换句话说,当你将一个基类连接到派生类时,必须在派生类的基类中调用一些构造函数。 基类总是首先通过调用基类中的某个构造函数从派生类实例化。 C#不关心它是一个默认的构造函数还是带有参数的非默认构造函数。 这就是为什么你可以省略一个默认的构造函数在你所有的类中,因为它被隐含地调用。只有在基类中没有添加带有参数的其他非构造函数。

当你突然添加一个非默认构造函数的参数,它打破了默认的默认构造函数链的创build和调用。 在具有非默认构造函数的Base类中,您现在必须显式地从派生类中调用该构造函数,或者在基类中显式地添加默认构造函数。

我们来testing一下…..

 // 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.对基类中的默认构造函数的调用隐式地在基类中创build,并从派生中隐式地调用,因为没有非默认构造函数已经添加到基类或2 。有一个显式调用非默认的,基于参数的构造函数使用base(myparamter)

  • 什么是混淆是什么时候和为什么默认的构造函数在基类中创build和派生类调用。 只有当非默认的构造函数出现在底部时才会发生这种情况。