none
Zugriff auf Basisklasse statt auf abgeleiteter RRS feed

  • Frage

  • Hallo alle,

    ich habe eine Unterklasse (frmDL800), die von der Hauptklasse (frmMain) und IDisposable erbt. Mit geerbt wird ein Button "Messwert speichern". Dieser Button ist in "Modifiers" auf protected gesetzt.

    In frmMain ist die Methode für das Click- Ereignis auf "private" gesetzt, und in frmDL800 mit "new" überschrieben. Zumindest theoretisch. Denn wenn ich in frmDL800 auf "Messwert speichern" klicke, wird die Methode aus frmMain aufgerufen, die ich so aber nicht gebrauchen kann.

    Was läuft da falsch?

    Grüße

      Heiko

    Mittwoch, 30. Januar 2013 15:09

Antworten

  • Hallo Heiko,

    Da läuft nichts falsch, wenn ich Deine Beschreibung richtig interpretiere - auch wenn es nicht Deiner Intention entspricht. Ereignisse funktionieren nämlich genau so.

    Die Behandlungsroutine in frmMain wird im InitializeComponent mit der Behandlungsroutine verknüpft. Direkt programmiert ohne es in InitializeComponent zu verstecken:

        public partial class frmMain : Form
        {
            protected Button MesswertSpeichernButton;
    
            public frmMain()
            {
                InitializeComponent();
    
                MesswertSpeichernButton = new Button()
                {
                    Bounds = new Rectangle(12, 12, 80, 24),
                    Text = "frmMain: Speichern"
                };
    
                this.MesswertSpeichernButton.Click += new System.EventHandler(MesswertSpeichernButton_Click);
                this.Controls.Add(MesswertSpeichernButton);
            }
    
            void MesswertSpeichernButton_Click(object sender, System.EventArgs e)
            {
                Console.WriteLine("frmMain: MesswertSpeichernButton_Click");
            }
        }

    Die Verdrahtung durch das registrieren des EventHandlers ist ab dem Moment fix. Der new Modifizierer kann daran nichts ändern, denn die die Methode in frmMain wird dadurch nicht ersetzt.

    Eine Möglichkeit wäre hier die Methode virtuell zu machen und davon abzuleiten:

            protected virtual void MesswertSpeichernButton_Click(object sender, System.EventArgs e)
            {
                Console.WriteLine("frmMain: MesswertSpeichernButton_Click");
            }

    und dann in frmDLL800:

        public partial class frmDL800 : frmMain
        {
            public frmDL800()
            {
                base.MesswertSpeichernButton.Text = "frmDL800: Speichern";
            }
    
            protected override void MesswertSpeichernButton_Click(object sender, EventArgs e)
            {
                // würde die ursprüngliche Routine aufrufen
                // base.MesswertSpeichernButton_Click(sender, e);
                Console.WriteLine("frmDL800: MesswertSpeichernButton_Click");
            }
        }

    Will man die Basisfunktionalität ebenfalls nutzen, so müsste man den auskommentierten Teil aktivieren.

    Gruß Elmar


    • Bearbeitet Elmar Boye Mittwoch, 30. Januar 2013 16:48
    • Als Antwort markiert Heiko Sturm Donnerstag, 31. Januar 2013 08:18
    Mittwoch, 30. Januar 2013 16:47

Alle Antworten

  • Hallo Heiko,

    Da läuft nichts falsch, wenn ich Deine Beschreibung richtig interpretiere - auch wenn es nicht Deiner Intention entspricht. Ereignisse funktionieren nämlich genau so.

    Die Behandlungsroutine in frmMain wird im InitializeComponent mit der Behandlungsroutine verknüpft. Direkt programmiert ohne es in InitializeComponent zu verstecken:

        public partial class frmMain : Form
        {
            protected Button MesswertSpeichernButton;
    
            public frmMain()
            {
                InitializeComponent();
    
                MesswertSpeichernButton = new Button()
                {
                    Bounds = new Rectangle(12, 12, 80, 24),
                    Text = "frmMain: Speichern"
                };
    
                this.MesswertSpeichernButton.Click += new System.EventHandler(MesswertSpeichernButton_Click);
                this.Controls.Add(MesswertSpeichernButton);
            }
    
            void MesswertSpeichernButton_Click(object sender, System.EventArgs e)
            {
                Console.WriteLine("frmMain: MesswertSpeichernButton_Click");
            }
        }

    Die Verdrahtung durch das registrieren des EventHandlers ist ab dem Moment fix. Der new Modifizierer kann daran nichts ändern, denn die die Methode in frmMain wird dadurch nicht ersetzt.

    Eine Möglichkeit wäre hier die Methode virtuell zu machen und davon abzuleiten:

            protected virtual void MesswertSpeichernButton_Click(object sender, System.EventArgs e)
            {
                Console.WriteLine("frmMain: MesswertSpeichernButton_Click");
            }

    und dann in frmDLL800:

        public partial class frmDL800 : frmMain
        {
            public frmDL800()
            {
                base.MesswertSpeichernButton.Text = "frmDL800: Speichern";
            }
    
            protected override void MesswertSpeichernButton_Click(object sender, EventArgs e)
            {
                // würde die ursprüngliche Routine aufrufen
                // base.MesswertSpeichernButton_Click(sender, e);
                Console.WriteLine("frmDL800: MesswertSpeichernButton_Click");
            }
        }

    Will man die Basisfunktionalität ebenfalls nutzen, so müsste man den auskommentierten Teil aktivieren.

    Gruß Elmar


    • Bearbeitet Elmar Boye Mittwoch, 30. Januar 2013 16:48
    • Als Antwort markiert Heiko Sturm Donnerstag, 31. Januar 2013 08:18
    Mittwoch, 30. Januar 2013 16:47
  • Hallo Elmar,

    danke, das funktioniert so schon mal.

    Was mich allerdings stutzig macht: die Methoden eines anderen Buttons (btnStop), die in beiden Formen als "private" deklariert sind, werden auch tatasächlich nur innerhalb ihrer Formen ausgeführt.

    Kann es sein, dass die Ursache beim btnMesswertSpeichern noch woanders liegt?

    Grüße

      Heiko

    Donnerstag, 31. Januar 2013 09:55
  • Hallo,

    private (entsprechend protected, internal, public) beeinflussen nur die Sichtbarkeit einer Methode. D. h. ob Du sie aus externen oder abgeleiteten Klassen aufrufen kannst.

    Jede (nicht virtuelle) Methode existiert in der Klasse in der sie definiert ist. So würde ist es ohne weiteres möglich gleiche Namen zu haben:

        public partial class frmMain : Form
        {
            private void Method1() { Console.WriteLine("frmMain: Method1"); }
        }
    
        public partial class frmDL800 : frmMain
        {
            private void Method1() { Console.WriteLine("frmDL800: Method1"); }
        }
    

    Verwendet man eine "höhere" Sichtbarkeit wie internal, protected oder public "meckert" der Compiler - aber auch nur weil das sehr wahrscheinlich nicht gewollt ist - und durch new überzeugt man ihn, dass man das doch will.

    Das ändert aber nichts daran, welche Methode für die Ereignis-Behandlung hinterlegt wird. Das ist die erste Methode, die in der Klasse (hier frmMain) sichtbar ist. Spätere Methoden heißen einfach nur gleich, sind aber unabhängig. (So wie auch andere "Heiko" heißen - aber deswegen längst nicht mit Dir verwandt sind ;)

    Erst wenn Du eine Methode virtuell machst, wird geguckt, ob es eine "bessere" Ableitung in abgeleiteten Klassen gibt.

    Mehr dazu (in anderen Worten): Wann müssen die Schlüsselwörter "override" und "new" verwendet werden? (C#-Programmierhandbuch)

    Gruß Elmar

    Donnerstag, 31. Januar 2013 10:53