Reihenfolge der Konstruktoraufrufe



  • Ich habe folgendes Programm:

    using System;
    using System.Collections.Generic;
    using System.Text;
    
    namespace Application
    {
        class Basis
        {
            static Basis()
            {
                Console.WriteLine("Statisch Basis");
            }
    
            public Basis()
            {
                Console.WriteLine("Normal Basis");
            }
        }
    
        class Abgeleitet : Basis
        {
            static Abgeleitet()
            {
                Console.WriteLine("Statisch Abgeleitet");
            }
    
            public Abgeleitet()
            {
                Console.WriteLine("Normal Abgeleitet");
            }
        }
    
        static class Program
        {
            static void Main()
            {
                Abgeleitet a=new Abgeleitet ();
    
                Console.ReadLine();
            }
        }
    }
    

    Nun bekomme ich die Ausgabe hier:

    Statisch abgeleitet
    Statisch Basis
    Normal Basis
    Normal Abgeleitet
    

    Warum jetzt der normale Konstruktor der abgeleiteten Klasse vor dem normalen Konstruktor der Basisklasse aufgerufen wird, verstehe ich: Die abgeleitete Klasse spezifiziert das Objekt noch mehr und wenn dort bei der Initialisierung irgendwelche Werte gesetzt werden, dürfen die ja nicht wieder durch den Basiskonstruktor überschrieben werden.
    Aber warum ist es bei den statischen Konstruktoren genau umgekehrt? Warum wird der statische Konstruktor der Basisklasse zuletzt aufgerufen?



  • Jeff Murdock schrieb:

    Die abgeleitete Klasse spezifiziert das Objekt noch mehr und wenn dort bei der Initialisierung irgendwelche Werte gesetzt werden, dürfen die ja nicht wieder durch den Basiskonstruktor überschrieben werden.

    Dies ist nur zum Teil richtig. Zum einen _kann_ der CTor der Basisklasse gar nicht auf Variablen der abgeleiteten Klasse zugreifen, also kann er diese auch nicht ändern.

    Umgekehrt sollte die abgeleitete Klasse keine Variablen der Basisklasse direkt ändern. Das macg zwar technisch möglich sein, ist aber ein unnötiger Bruch der Kapselung. Sauberer gehts so:

    class Basis
    {
       int Variable;
    
       public Basis(int var)
       { 
          Variable = var;
       }
    }
    
    class Abgeleitet : Basis
    {
       public Abgeleitet(int var)
          : basis(var)
      {
      }
    }
    

    Jeff Murdock schrieb:

    Aber warum ist es bei den statischen Konstruktoren genau umgekehrt? Warum wird der statische Konstruktor der Basisklasse zuletzt aufgerufen?

    Das interpretierst Du falsch. Static Ctors werden nicht aufgerufen wenn ein Object erzeugt wird (wie die normalen Ctors), sondern beim ersten Zugriff/Benutzung der Klasse getriggert.

    http://msdn2.microsoft.com/en-us/library/aa645612(VS.71).aspx

    Der erste Zugriff erfolgt ja auf Abgeleitet wenn ein Objekt der Klasse erzeugt wird, also wird der statsiche aufgerufen. Der Ctor von Abgeleitet ruft dann den Ctor von Basis auf, wodurch der staticCtor von Basis getriggert wird.

    Btw, static Ctors werden nur ein einziges mal aufgerufen pro Klasse. Würdest Du z.B. sowas machen vor dem new:

    Basis.SomeStaticFunction();
      Abgeleitet.SomeStaticFunction();
    

    Wäre die Reihenfolge der static Ctor ausgaben in der Reihenfolge der beiden Funktionsaufrufe.



  • oks schrieb:

    Dies ist nur zum Teil richtig. Zum einen _kann_ der CTor der Basisklasse gar nicht auf Variablen der abgeleiteten Klasse zugreifen, also kann er diese auch nicht ändern.

    Das weiß ich natürlich. Ich meinte, wenn ich in der Basisklasse eine Variable habe und diese im (normalen) Konstruktor der abgeleiteten Klasse gesetzt wird, wäre es nicht sinnvoll, dass die Sprache so definiert ist, dass als letztes der Basiskonstruktor aufgerufen wird, denn dann würden die Initialisierungen im Abgeleitet-Konstruktor, die sich auf Attribute der Basisklasse beziehen, null und nichtig sein.

    oks schrieb:

    Umgekehrt sollte die abgeleitete Klasse keine Variablen der Basisklasse direkt ändern. Das macg zwar technisch möglich sein, ist aber ein unnötiger Bruch der Kapselung.

    Wieso? Wenn die Variable protected ist, ist es doch direkt so gedacht, dass abgeleitete Klassen sie benutzen können.
    Wenn ich zum Beispiel eine Bitmapklasse habe, deren Breite und Höhe im Konstruktor auf jeweils 1 Pixel und deren Farbtiefe auf 24 Bit gesetzt wird, dann wäre es durchaus denkbar, dass im Konstruktor der Klasse Icon, die von Bitmap erbt, die Größe mit jeweils 16 Pixeln und die Farbtiefe mit 16 Farben initialiaisert wird, weil das die Standardwerte bei Icons sind.
    Ja, ich weiß, eigentlich müsste einer der Bitmap-Konstruktoren so gebaut sein, dass er diese Werte entgegennehmen kann, so dass man diesen Konstruktor aufruft. Vielleicht kein ideales Beispiel. Hier ein anderes:

    Eine Klasse Mensch mit Statusattribut, das entweder Säugling, Kleinkind, Kind, Jugendlicher oder Erwachsener sein kann und das im Konstruktor immer mit Säugling initialisiert wird.
    Dann eine von Mensch abgeleitete Klasse DirektGeschaffenerMensch (Adam und Eva), wo der Status mit Erwachsener initialisiert wird.

    oks schrieb:

    Das interpretierst Du falsch. Static Ctors werden nicht aufgerufen wenn ein Object erzeugt wird (wie die normalen Ctors), sondern beim ersten Zugriff/Benutzung der Klasse getriggert.

    http://msdn2.microsoft.com/en-us/library/aa645612(VS.71).aspx

    Der erste Zugriff erfolgt ja auf Abgeleitet wenn ein Objekt der Klasse erzeugt wird, also wird der statsiche aufgerufen. Der Ctor von Abgeleitet ruft dann den Ctor von Basis auf, wodurch der staticCtor von Basis getriggert wird.

    Klar, das verstehe ich. Dann hab ich es wirklich falsch interpretiert.



  • Jeff Murdock schrieb:

    oks schrieb:

    Umgekehrt sollte die abgeleitete Klasse keine Variablen der Basisklasse direkt ändern. Das macg zwar technisch möglich sein, ist aber ein unnötiger Bruch der Kapselung.

    Wieso? Wenn die Variable protected ist, ist es doch direkt so gedacht, dass abgeleitete Klassen sie benutzen können.

    Nein. Das geht zwar, ist aber schlechter Stil. Felder sollten immer als 'private' deklariert sein. Nur Properties und Methoden können auch 'protected' sein.


Anmelden zum Antworten