it-swarm.com.de

Wird der Basisklassenkonstruktor automatisch aufgerufen?

class Person
{
    public int age;
    public Person()
    {
        age = 1;
    }
}

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

Customer customer = new Customer();

Würde das Kundenalter 2 Jahre alt sein? Es scheint, als würde der Konstruktor der Basisklasse auf jeden Fall aufgerufen werden. Wenn ja, warum müssen wir manchmal base am Ende aufrufen?

public Customer() : base()
{
    .............
}
80
Ivan Li

So funktioniert C # einfach. Die Konstruktoren für jeden Typ in der Typhierarchie werden in der Reihenfolge Most Base -> Most Abived aufgerufen. 

In Ihrer speziellen Instanz werden also Person() und dann Customer() in den Konstruktoraufträgen aufgerufen. Der Grund, warum Sie manchmal den Konstruktor base verwenden müssen, ist, wenn die Konstruktoren unter dem aktuellen Typ zusätzliche Parameter benötigen. Zum Beispiel:

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

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

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

Um ein AlwaysThreeDerived-Objekt zu erstellen, verfügt es über einen parameterlosen Konstruktor. Der Base-Typ ist jedoch nicht möglich. Um einen parameterlosen Konstruktor zu erstellen, müssen Sie dem Basiskonstruktor ein Argument zur Verfügung stellen, das Sie mit der base-Implementierung ausführen können.

74
Tejs

Ja, der Basisklassenkonstruktor wird automatisch aufgerufen. Sie müssen base() keinen expliziten Aufruf hinzufügen, wenn ein Konstruktor ohne Argumente vorhanden ist.

Sie können dies einfach testen, indem Sie das Alter des Kunden nach der Konstruktion ausdrucken ( Link zu Ideone mit Demo ).

44
dasblinkenlight

Wenn Sie keinen parameterlosen Standardkonstruktor haben, müssen Sie den Parameter mit Parametern aufrufen:

class Person
{
    public Person(string random)
    {

    }
}

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

    }
}
11
Science_Fiction

base()wird standardmäßig aufgerufen, kann aber auch für andere Zwecke verwendet werden:

  1. base () `Methode wird verwendet, um den Wert an das übergeordnete Klassenkonstrukt oder zu übergeben
  2. um den Konstruktor no-arg der übergeordneten Klasse aufzurufen.

zum Beispiel:

Fall 1: wenn der übergeordnete Parameter einen parametrisierten Konstruktor hat, aber kein Standard- oder kein Argon-Konstruktor.  

 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;
    }
}

Fall 2: Wenn übergeordnetes Element mehr als einen Konstruktor enthält, wird standardmäßig ein Konstruktor verwendet.

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;
    }
}

Hier rufen wir manuell einen no-arg-Konstruktor von base () auf, um einige Intilisierungen durchzuführen, aber keinen Wert übergeben.

Hoffe, das wird dir helfen. 

3
Prakash Sharma

Bei Verwendung von Basis- und abgeleiteten Klassen in C # MUSS EINIGE IMPLICIT OR EXPLICIT-AUFRUF AN EINIGE KONSTRUKTOR IN DER BASISKLASSE DER DERIVIERTEN KLASSE ERFORDERN.

Ich habe nicht verstanden, wie das alles funktionierte, bis ich diese Tatsache erkannte.

Wenn Sie also eine Basisklasse mit einer abgeleiteten Klasse verbinden, muss in der Basisklasse ein Konstruktor aus der abgeleiteten Klasse aufgerufen werden. Die Basisklasse wird immer zuerst von der abgeleiteten Klasse über einen Aufruf an einen Konstruktor in der Basisklasse instanziiert. C # ist es egal, ob es sich um einen Standardkonstruktor oder einen nicht standardmäßigen Konstruktor mit Parametern handelt. Aus diesem Grund können Sie einen Standardkonstruktor in allen Klassen weglassen, da er implizit NUR genannt wird, wenn in der Basisklasse kein anderer Nichtkonstruktor mit Parametern hinzugefügt wird.

Wenn Sie plötzlich einen nicht standardmäßigen Konstruktor mit Parametern hinzufügen, unterbricht er die standardmäßig erstellte Standardkonstruktorkettenerstellung und -aufrufe. In Ihrer Basisklasse mit einem nicht standardmäßigen Konstruktor müssen Sie jetzt entweder diesen Konstruktor explizit von der abgeleiteten Klasse aufrufen oder einen Standardkonstruktor explizit in der Basisklasse hinzufügen.

Lass uns das testen .....

// 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
    //{
    //}
}

Der Grund, warum alle oben genannten Elemente funktionieren, ist entweder: 1. Der Aufruf des Standardkonstruktors in der Basisklasse wird implizit in der Basisklasse erstellt und implizit aus dem abgeleiteten Aufruf aufgerufen, da der Basisklasse oder .__ kein Nicht-Standardkonstruktor hinzugefügt wurde. Es gibt einen expliziten Aufruf an einen nicht standardmäßigen, parameterbasierten Konstruktor, der base (myparamter) verwendet.

  • Verwirrend ist, wann und warum Standardkonstruktoren in Basisklassen erstellt und von abgeleiteten Klassen aufgerufen werden. Dies ist nur der Fall, wenn in der Basis KEINE nicht standardmäßigen Konstruktoren angezeigt werden.
2
Stokely

Ich habe nicht viel hinzuzufügen, aber ich habe festgestellt, dass ich MyConstructor (): base () ohne Parameter in einem Fall aufrufen muss. Ich habe eine Basisklasse, die INotifyPropertyChanged so implementiert, dass ich eine virtuelle Funktion RegisterProperties () habe. Wenn ich es überschreibe, wird es im Basiskonstruktor aufgerufen. Ich muss es also in den zuletzt abgeleiteten Unterklassen aufrufen, da die Basis anscheinend aufgerufen wurde, bevor die überschriebene virtuelle Zelle erkannt wurde. Meine Eigenschaften benachrichtigen nicht, wenn ich dies nicht mache. Die gesamte Basisklasse befindet sich unten.

Ich habe eine DatabaseTraits-Unterklasse direkt darunter hinzugefügt. Ohne den leeren Aufruf von base () rufen meine Eigenschaften OnPropertyChanged () nicht auf.

[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
steviesama