Будет ли конструктор базового класса вызываться автоматически?


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()
{
    .............
}
6 66

6 ответов:

это просто, как C# будет работать. Конструкторы для каждого типа в иерархии типов будут вызываться в порядке Most Base - > Most Derived.

поэтому в вашем конкретном случае он вызывает 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 объект, он имеет конструктор без параметров. Тем не менее,Base тип не. Поэтому для того, чтобы создать конструктор без параметров, вам нужно предоставить аргумент базовому конструктору, который вы можете сделать с помощью base реализация.

да, конструктор базового класса вызывается автоматически. Вам не нужно добавлять явный вызов base() когда есть конструктор без аргументов.

вы можете легко проверить это, распечатав возраст клиента после строительства (ссылка на ideone с демо).

Если бы у вас не было конструктора без параметров по умолчанию, тогда нужно было бы вызвать тот, у которого есть параметры:

class Person
{
    public Person(string random)
    {

    }
}

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

    }
}

base() называется по умолчанию, но он может быть использован для других целей, таких как :

  1. base()` метод используется для передачи значения в родительский класс построить или
  2. для вызова конструктора no-arg родительского класса .

например:

Случай 1: если родитель имеет параметризованный конструктор, но не конструктор по умолчанию или No-arg.

 class Person
 {

    private string FirstName;
    private string LastName;
    private string EmailAddress;
    private DateTime DateOfBirth;

    public Person(string firstName, string lastName, string emailAddress, DateTime dateOfBirth)
    {
        FirstName = firstName;
        LastName = lastName;
        EmailAddress = emailAddress;
        DateOfBirth = dateOfBirth;

    }
    }
class Employee : Person
{
    private double Salary { get; set; } = 0;

    public Employee(string firstName, string lastName, string emailAddress, DateTime dateOfBirth,double salary)
        :base(firstName,lastName,emailAddress,dateOfBirth)// used to pass value to parent constructor and it is mandatory if parent doesn't have the no-argument constructor.
    {
        Salary = salary;
    }
}

случай 2: когда родитель имеет больше чем один конструктор вместе с конструктором по умолчанию.

class Person
{

    private string FirstName;
    private string LastName;
    private string EmailAddress;
    private DateTime DateOfBirth;

    public Person()
    {
        // some important intialization's to be done  

    }

    public Person(string firstName, string lastName, string emailAddress, DateTime dateOfBirth)
    {
        FirstName = firstName;
        LastName = lastName;
        EmailAddress = emailAddress;
        DateOfBirth = dateOfBirth;

    }
    }
class PermanentEmployee : Person
{
    public double HRA { get; set; }
    public double DA { get; set; }
    public double Tax { get; set; }
    public double NetPay { get; set; }
    public double TotalPay { get; set; }

    public PermanentEmployee(double hRA, double dA, double tax, double netPay, double totalPay) : base();
    {
        HRA = hRA;
        DA = dA;
        Tax = tax;
        NetPay = netPay;
        TotalPay = totalPay;
    }
}

здесь мы вызываем конструктор no-arg вручную с помощью base () для выполнения некоторых внедрений, но не передаем никакого значения.

надеюсь, что это поможет вам.

В c# с использованием базового и производного классов должен быть некоторый неявный или явный вызов некоторого конструктора в базовом классе из производного класса.

другими словами, при подключении базового класса к производному классу, какой конструктор должен быть вызван в базового класса из производного. Базовый класс всегда создается первым из производного класса с помощью вызова некоторого конструктора в производном классе. базовый класс. C# не имеет значения, является ли он конструктором по умолчанию или конструктором не по умолчанию с параметрами. Вот почему вы можете оставить конструктор по умолчанию во всех ваших классах как его неявно вызываемый только в том случае, если в базовый класс не добавлен другой не-конструктор с параметром(АМИ).

когда вы внезапно добавляете конструктор не по умолчанию с параметром(АМИ), он нарушает создание и вызовы цепочки скрытых конструкторов по умолчанию по умолчанию. В базовый класс без конструктора по умолчанию вы должны теперь либо вызовите этот конструктор явно из производного класса, либо добавьте конструктор по умолчанию явно в базовый класс.

давайте проверим это.....

// 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)

  • что сбивает с толку, когда и почему конструкторы по умолчанию создаются в базовых классах и вызываются из производных классов. Это происходит только в том случае, если в базе нет нестандартных конструкторов.

Мне нечего добавить, но я обнаружил, что мне нужно вызвать MyConstructor() : base() без параметров в 1 случае. У меня есть базовый класс, который реализует INotifyPropertyChanged таким образом, где у меня есть виртуальная функция RegisterProperties (). Когда я переопределяю его, он вызывается в базовом конструкторе. Поэтому мне приходится вызывать его в самых последних производных подклассах, потому что база, по-видимому, была вызвана до того, как переопределенный виртуальный был распознан. Мои свойства не уведомляют, если я не делаю этот. Весь базовый класс находится ниже.

Я добавил подкласс DatabaseTraits непосредственно под ним. Без вызова пустой базы () мои свойства не вызывают 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
}