[Novize] Delegaten Methodenreihenfolge unorthodox?



  • Hey Leute!

    Ich bin zurzeit in einem Lehrgang für C# und habe da eine kleine Denkschwäche was Delegaten angeht.
    Der Programmablauf und die Ausgabe entsprechen beide der Vorgabe des Lernheftes - somit habe ich die Aufgabe richtig gelöst.
    Jedoch ist mir die Lösung nicht ganz schlüssig und darum folgende Frage:

    (Ich hoffe der Codeauszug reicht aus...)

    Die Reihenfolge der Methodenaufrufe (welche in der Delegate gespeichert werden) scheinen mir nicht schlüssig.

    Laut meiner Erkenntnis, Beispiel ab Zeile 58, wird von der Instanz flieger1.Steuern() der Delegat aufgerufen. Dort wird dann die erste Methode aufgerufen die ja im Konstruktor von flieger1 paralell dem Delegat zugewiesen wurde.
    Der Methodenaufruf erfährt durch die Bedingung dann das die "kennung" der Laufzeit und die "kennung" des Parameters der Methode übereinstimmen. Somit stimmt auch Ausgabe Zeile 3.
    Jedoch müsste laut meiner Logik dann auch die zweite Methode aufgerufen werden. Denn der Konstruktor für flieger2 fügt dem Delegat ja die nächste Methode zu.
    Ich gehe dann davon aus das bei der Instanz flieger1 und dessen Aufruf von Steuern() nach der ersten Methode dann auch die zweite, gespeicherte Methode aufgerufen wird.
    Jedoch passiert was ganz anderes.
    Er springt anscheinend zur Instanz flieger2. Führt dort Steuern() aus und aktiviert dort wiederum die erste Methode.
    Nun fängt er wieder bei flieger1 an und führt dort die zweite Methode des Delegat aus.
    Woher ich das weiss? Ganz einfach nachvollziehbar durch die Konsolenausgabe.
    Leider hat das Lernheft nie das Verhalten bei der Reihenfolge einer Delegate erklärt und ich stehe im dunklen.
    Oder...
    Ich interpretiere die Konsolenausgabe total falsch und eigentlich wird alles richtig ausgeführt 😃
    Kann aber nicht sein denn "LH 500" ist die Laufzeit this.kennung und somit kann es sich nur um die erste Methode handeln bei der flieger2.kennung != flieger1.kennung wäre.

    Ach Jungs/Mädels, ihr merkt ich hab hier ne happige Denklücke und hoffe ihr fischt mich mit freude da wieder heraus 😉

    Hier le Codé

    class Starrflügelflugzeug : Flugzeug, ITransponder
        {
            public void Steuern()
            {
                Program.transponder(kennung, pos);
            }
            public Starrflügelflugzeug(string kennung, Position pos)
                : base(kennung, pos)
            {
                Program.transponder += Transpond;
            }
            // Implementierung der Interface-Methode (Aufgabe 5.7)
            public void Transpond(string kennung, Position pos)
            {
                if(this.kennung == kennung)
                    Console.WriteLine(this.kennung + " erkennt Eingang eigenes Signal.");
                else
                    Console.WriteLine(this.kennung
                        + " empfängt Position von " + kennung + "x=" + pos.x + ", y=" + pos.y + ", h=" + pos.h);
    
            }
        }
        class Düsenflugzeug : Starrflügelflugzeug
        {
            private int sitzplätze;
            private int fluggäste;
            public int Fluggäste
            {
                set
                {
                    if (sitzplätze < (fluggäste + value))
                        Console.WriteLine("Keine Buchung: Die Fluggastanzahl würde mit der Zubuchung von {0} Plätzen"
                            + " die verfügbaren Plätze von {1} um {2} übersteigen!", value, sitzplätze, value + fluggäste - sitzplätze);
                    else
                        fluggäste += value;
                }
                get { return fluggäste; }
            }
            public Düsenflugzeugtyp typ;
            public Düsenflugzeug(string kennung, Position pos, Düsenflugzeugtyp typ)
                : base(kennung, pos)
            {
                this.typ = typ;
                sitzplätze = (int)typ;
            }
            public void buchen(int plätze)
            {
                Fluggäste = plätze;
            }
        }
        class Program
        {
            public void TransponderTest()
            {
                Starrflügelflugzeug flieger1 = new Starrflügelflugzeug("LH 3000", new Position(3000, 2000, 100));
                flieger1.Steuern();
                Console.WriteLine();
                Starrflügelflugzeug flieger2 = new Starrflügelflugzeug("LH 500", new Position(3500, 1500, 180));
                flieger1.Steuern();
                flieger2.Steuern();
                Console.WriteLine();
                Starrflügelflugzeug flieger3 = new Starrflügelflugzeug("LH 444", new Position(17300, 23400, 780));
                flieger1.Steuern();
                flieger2.Steuern();
                flieger3.Steuern();
                Console.WriteLine();
                //Flieger 2 beim Delegaten Objekt abmelden:
                transponder -= flieger2.Transpond;
                flieger1.Steuern();
                flieger2.Steuern();
                Console.WriteLine();
            }
    

    Konsolenausgabe:

    LH 3000 erkennt Eingang eigenes Signal.
    
    LH 3000 erkennt Eingang eigenes Signal.
    LH 500 empfängt Position von LH 3000x=3000, y=2000, h=100
    LH 3000 empfängt Position von LH 500x=3500, y=1500, h=180
    LH 500 erkennt Eingang eigenes Signal.
    
    LH 3000 erkennt Eingang eigenes Signal.
    LH 500 empfängt Position von LH 3000x=3000, y=2000, h=100
    LH 444 empfängt Position von LH 3000x=3000, y=2000, h=100
    LH 3000 empfängt Position von LH 500x=3500, y=1500, h=180
    LH 500 erkennt Eingang eigenes Signal.
    LH 444 empfängt Position von LH 500x=3500, y=1500, h=180
    LH 3000 empfängt Position von LH 444x=17300, y=23400, h=780
    LH 500 empfängt Position von LH 444x=17300, y=23400, h=780
    LH 444 erkennt Eingang eigenes Signal.
    
    LH 3000 erkennt Eingang eigenes Signal.
    LH 444 empfängt Position von LH 3000x=3000, y=2000, h=100
    LH 3000 empfängt Position von LH 500x=3500, y=1500, h=180
    LH 444 empfängt Position von LH 500x=3500, y=1500, h=180
    
    Drücken Sie eine beliebige Taste . . .
    


  • Es wird alles korrekt ausgeführt.
    Sobald in Zeile 58 sowohl der Konstruktor für flieger1 als auch flieger2 aufgerufen worden sind, sind beide Ereignismethoden registriert und werden dann bei flieger1.Steuern() und flieger2.Steuern() jeweils ausgegeben (Zeilen 3/4 und 5/6 deiner Konsolenausgabe). Die Reihenfolge entspricht dabei der Registrierung, d.h. jeweils erst für flieger1, dann für flieger2.

    Und nachdem flieger3 registriert ist, werden dann jeweils 3 Zeilen je Steuern()-Aufruf ausgegeben (Zeile 8 - 16).

    Und nach dem Deregistrieren von flieger2 dann nur noch jeweils für flieger1 und flieger3.
    Und wie du siehst, ist es egal für welche Flieger-Instanz du dessen Steuern()-Methode aufrufst, es werden immer alle registrierten (bzw. man nennt dies eigentlich 'abonnierten') Ereignismethoden aufgerufen (ein Delegat speichert intern auch die zugehörige Instanz, für die es registriert wurde - im Gegensatz z.B. zu Klassenmethodenzeigern in C++, wo erst beim Aufruf die Instanz festgelegt wird).


Log in to reply