Autor Beitrag
Dingo
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 64
Erhaltene Danke: 1



BeitragVerfasst: Mi 21.06.17 08:35 
Grüße!

Mal eine Frage zu Delegates, die sehen ja normalerweise so aus:

ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
namespace DelegatesBeispiel2 {

    delegate void DelagateMethode(string text); 

    class Program {
        
        // Drei im Delage zu speichernde Methoden
        private void Textausgabe1(string text) {
            Console.WriteLine("Textausgabe 1 sagt: {0}",    
            text);
        }

        private void Textausgabe2(string text) {
            Console.WriteLine("Textausgabe 2 sagt: {0}"
            text);
        }

        private void Textausgabe3(string text) {
            Console.WriteLine("Textausgabe 3 sagt: {0}",     
            text);
        }


        public void DelegateStart() {
            DelagateMethode del = new  
            DelagateMethode(Textausgabe1);
            del += Textausgabe2;
            del += Textausgabe3;
            del("Hallo du da!");     
        }

        static void Main(string[] args) {
            Program test = new Program();
            test.DelegateStart();
            Console.ReadLine();
        }
    }
}


Also mit Parametern. Nun habe ich mal zum Testen versucht ein Delegates ohne Parameter zu erstellen und die zugeordneten Methoden wurden nicht aufgerufen. Brauchen demnach Delegates immer einen Parameter oder habe ich da etwas falsch gemacht?
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Mi 21.06.17 08:49 
Hallo,

die Methodensignatur muß dann auch übereinstimmen, d.h. der Rückgabewert und die Methodenparameter.

Wenn du also ein Delegate ohne Parameter erstellst:
ausblenden C#-Quelltext
1:
delegate void DelegateMethode(); // Schreibfehler in deinem Namen korrigiert ;-)					

dann kannst du damit auch nur Methoden ohne Parameter zuweisen und aufrufen:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
void Test()
{
    Console.WriteLine("Test");
}

public void DelegateStart()
{
    DelegateMethode del = new DelegateMethode(Test);
    del += Test;
    del += Test;
    del(); // Aufruf
}

Für diesen Beitrag haben gedankt: Dingo
Dingo Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 64
Erhaltene Danke: 1



BeitragVerfasst: Mi 21.06.17 09:10 
Also ich habs mal ausprobiert, bekomme aber nur einen blinkenden Cursor als Antwort:

ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;

    namespace DelegatesBeispiel2 {

        delegate void DelagateMethode();

        class Program {

            private void Textausgabe1() {
                Console.WriteLine("Textausgabe 1 sagt nichts!");
            }

            private void Textausgabe2() {
                Console.WriteLine("Textausgabe 2 sagt nichts!");
            }

            private void Textausgabe3() {
                Console.WriteLine("Textausgabe 3 sagt nichts!");
            }

            public void DelegateStart() {
                DelagateMethode del = new DelagateMethode(Textausgabe1);
                del += Textausgabe2;
                del += Textausgabe3;
                Console.ReadLine();
            }

            static void Main(string[] args) {
                Program test = new Program();
                test.DelegateStart();
            }
        }
    }


EDIT:

Übersehen, der Aufruf fehlte: del();

Danke! :)
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mi 21.06.17 20:04 
Du hast an der Variablen del auch nur weitere Methoden hinzugefügt. Der delegat muß aber auch ausgeführt werden.
Ruf mal del(); auf. Dann solltest du sehen das deine drei Methoden aufgerufen werden.
Dingo Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 64
Erhaltene Danke: 1



BeitragVerfasst: Mi 28.06.17 09:54 
Jetzt hab ich noch einmal eine Nachfrage. Dies wäre mein Script:

ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
namespace EigenTest1 {
    class Program {
        static void Main(string[] args) {

            ThreadStart del = new ThreadStart(TestMethod1);

            Thread thread1 = new Thread(del);
            Thread thread2 = new Thread(new ParameterizedThreadStart(TestMethod2));
            thread1.Start();
            thread2.Start(22);
            
            for (int i = 0; i <= 100; i++) {
                for (int k = 1; k <= 200; k++) {
                    Console.Write("Y");
                }
                Console.ReadLine();
            }
            
        }

        public static void TestMethod1() {
            for (int i = 0; i <= 100; i++) {
                for (int k = 1; k <= 20; k++) {
                    Console.Write("X");
                }
                Console.WriteLine("Sekundär-Thread 1 " + i);
            }
        }

        public static void TestMethod2(object data) {
            for (int i = (int)data; i <= 100; i++) {
                for (int k = 1; k <= 30; k++) {
                    Console.Write("Z");
                }
                Console.WriteLine("Sekundär-Thread 2 " + i);
            }
        }

    }
}


Was ich nicht ganz verstehe ist das:

ausblenden C#-Quelltext
1:
ThreadStart del = new ThreadStart(TestMethod1);					


Was ist eigentlich ThreadStart? Es wird ja ein Delegate erzeugt, ist dies ein spezielles Delagete?

Aus ThreadStrart erzeuge ich ja das Objekt del, welches über:

ausblenden C#-Quelltext
1:
Thread thread1 = new Thread(del);					


dem Thread "thread1" zugeordnet wird. Theoretisch kann ich doch aber auch statt del eine Methode oder ein anderes Delegate eintragen. Warum nutzt man hier genau ThreadStart?

Des weiteren, benötigt ein Thread immer einen Delagete um zu arbeiten?

-----------------------------------------------------------------------------------------

Des weiteren "Wait" und "Pulse"

Geschrieben würde es ja so werden:

ausblenden C#-Quelltext
1:
2:
Monitor.Wait(del);
Monitor.Pulse(del);


Was ich nun nicht verstehe, warum muss ich bei beiden ein Objekt als Parameter angeben? Bei "Wait" verstehe ich das, es soll ja ein bestimmtes Objekt in den Wartezustand versetzt werden. Jedoch warum muss ich bei "Pulse" auch ein Objekt angeben? In meinem Buch steht, dass mit Pulse ein mehr oder weniger beliebiger Thread nach Pulse gestartet wird. Warum bezeiehe ich mich dann aber auf das Objekt del?
Frühlingsrolle
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mi 28.06.17 10:40 
- Nachträglich durch die Entwickler-Ecke gelöscht -

Für diesen Beitrag haben gedankt: Dingo
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Mi 28.06.17 11:29 
Hallo Dingo,

du kannst auch direkt den Methodennamen angeben:
ausblenden C#-Quelltext
1:
2:
3:
4:
Thread thread1 = new Thread(TestMethod1);
Thread thread2 = new Thread(TestMethod2);
thread1.Start();
thread2.Start(22);

s.a. Ideone - Test code (Beispiel aus Thread-Konstruktor: (ParameterizedThreadStart)).

Und bzgl. der Monitor-Methoden: diese erwarten doch gar keinen Delegate, sondern ein beliebiges Objekt, welches zur Synchronisation benutzt wird (und ohne diesen Parameter könnte man ja gar nicht verschiedene Objekte nutzen und/oder verschachtelte Aufrufe durchführen). Dies sollte aber nicht hier weiter diskutiert werden, ansonsten eröffne ein neues Thema dazu.

Für diesen Beitrag haben gedankt: Dingo
Dingo Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 64
Erhaltene Danke: 1



BeitragVerfasst: Mi 28.06.17 11:56 
Erst mal Danke für eure Rückantworten! :)

Ich hab heir noch ein Beispiel aus meinem Lehrheft:

ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
namespace ThreadpoolSample2 {
    class Program {
        static void Main(string[] args) {
            Demo obj = new Demo();

            Thread thread1, thread2;
            thread1 = new Thread(new ThreadStart(obj.Worker));
            thread2 = new Thread(new ThreadStart(obj.Worker));
            thread1.Start();
            thread2.Start();
            Console.WriteLine();
            Monitor.Pulse(obj);
        }
    }

    class Demo {
        private int value;

        public void Calculate(){}

        public void Worker() { 
            while (true){
                // Sperre setzen
                Monitor.Enter(this);
                value++;
                if (value > 100break;
                    Console.WriteLine(value);
                Monitor.Exit(this);
            }
        }
    }
}


Irgendwie hänge ich mich noch etwas an "ThreadStart" auf.

ausblenden C#-Quelltext
1:
public delegate void ThreadStart();					


Verstehe, hier kann ich jede Methode eintragen, die ein void ist und keine Parameter hat, Klammern sind ja leer.

Schauen wir uns mal das hier an:

ausblenden C#-Quelltext
1:
thread1 = new Thread(new ThreadStart(obj.Worker));					


thread1 ist der Name meines Threads der initialisiert wird, aber was macht der kleine Teil genau:

ausblenden C#-Quelltext
1:
new ThreadStart(obj.Worker)					


Warum schreibe ich nicht gleich das ganze so:

ausblenden C#-Quelltext
1:
thread1 = new Thread(obj.Worker);					


Wird mir zumindest nicht als Fehler ausgegeben und "ThreadStart" kommt ja so weit ich weiß als Klasse aus "using System.Threading;".

Irgendwie steh ich gerade auf dem schlauch.^^"

-------------------------------

Zu Delegate noch mal direkt: Ich habe es so verstanden, dass man Methoden mit dem gleichen Rückgabetyp in einem Delegate speichern kann. Man kann also mit einem Delegate mehrere Methoden über ein Delegate aufrufen. Versteh ich das korrekt?


--------------------------------

user profile iconTh69 hat folgendes geschrieben Zum zitierten Posting springen:
Hallo Dingo,

du kannst auch direkt den Methodennamen angeben:
ausblenden C#-Quelltext
1:
2:
3:
4:
Thread thread1 = new Thread(TestMethod1);
Thread thread2 = new Thread(TestMethod2);
thread1.Start();
thread2.Start(22);

Also ist das mal wieder in meinem Lernheft zwei Dinge an einem Beispiel erklären. Somit kann ich also Threads nutzen, ohne eine Delegate zu erstellen?
Frühlingsrolle
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mi 28.06.17 13:02 
- Nachträglich durch die Entwickler-Ecke gelöscht -

Für diesen Beitrag haben gedankt: Dingo
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mi 28.06.17 13:07 
Zitat:
Warum schreibe ich nicht gleich das ganze so:


Warum du es so nicht tust weiß ich nicht. Ich würde es so tun ;)

Du hängst hier so ein bißchen an der Entwicklungshistorie der Sprache. Die war ja nicht gleich von Anfang so wie jetzt und schon gar nicht perfekt.
Und hier geht es um die Intelligenz des Compilers. In früheren Version des Compilers mußte man den Delegaten immer explizit angeben. Der Compiler war nicht schlau genug um sich die Methoden anzusehen und den benötigten Delegatentypen daraus abzuleiten. Heutzutage braucht man das nicht. Der Compiler ist schlau genug sich die Methodensignatur anzusehen und zu erkennen ja die passt zu einem der hier erlaubten Delegaten (Aka zu Methodensignaturen die hier zulässig sind).

Um Delegaten zu erklären gehen heutige Lehrbücher vermutlich so vor das sie den expliziten Weg zeigen. Der implizite ist aber schon lange möglich und würde heutzutage auch eigentlich jeder so machen.
Du darfst also heutzutage (ich glaube seit c# 2 also seit mehr als 10! Jahren) anstatt
ausblenden C#-Quelltext
1:
thread1 = new Thread(new ThreadStart(obj.Worker));					

auch einfach
ausblenden C#-Quelltext
1:
thread1 = new Thread(obj.Worker);					

schreiben weil der Compiler sich die Signatur deiner Worker Methode ansieht und daran entscheiden kann ob die zu ThreadStart oder ParametrizedThreadStart passt und dann für dich im Hintergrund einfach das passende erledigt ohne das du es noch hinschreiben mußt.

Für diesen Beitrag haben gedankt: Dingo
Dingo Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 64
Erhaltene Danke: 1



BeitragVerfasst: Fr 30.06.17 08:25 
Oh man, wie froh ich bin, dass es dieses Forum gibt! :D

Danke euch vielmals, ihr habt mir nen rießen Knoten aus dem Kopf geholt, jetzt wird so einiges klarer! :)

Gerade das hilft mir gerade wahnsinnig weiter, dass ganze zu verstehen:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
// Variante 1
thread1 = new Thread(new ThreadStart(obj.Worker)); 

// Variante 2
ThreadStart start = new ThreadStart(obj.Worker);
thread1 = new Thread(start);

// Variante 3
thread1 = new Thread(obj.Worker);


Alle drei Varianten wurden in meinem Lehrbuch verwendet, dass dies alles das selbe es, auf die Idee kam ich nicht.^^
Dingo Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 64
Erhaltene Danke: 1



BeitragVerfasst: Di 04.07.17 10:11 
Noch einmal eine Nachfrage zu diesem Stück Code:

Ich erzeuge ein Delegate namens "TransponderDel" und davon ein Objekt mit dem Namen "transponder" in der Klasse "Program".
Wenn ein Flieger-Objekt initialisiert wird, wird die Konstruktormethode des Starrflügelflugzeugs aufgerufen und dem TranponderDel-Objekt "transponder" die Methpde "Transpond" zugewiesen. Danch wird mit z.B. flieger1.(Steuern) das Delegate-Objekt mit "Program.transponder(Kennung, pos);" aufgerufen. Bis hier hin ist es ja klar, er übergibt dann die Kennung und die Position an die Methode.

Jedoch werden auch andere Flugzeug-Objekte initialisiert. Woher weiß nun die Methode die ganzen Informationen und kann kennung und this.kennung mit einander vergleichen?



ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
class Starrflügelflugzeuge : Flugzeug, ITransponder {

        // Konstruktormethode
        public Starrflügelflugzeuge(string kennung, Position pos) : base(kennung, pos) {
            Program.transponder += new Program.TransponderDel(Transpond);
        }

        // Implementierung der Interface - Methode
        public void Transpond(string kennung, Position pos) {
            if (kennung.Equals(this.Kennung)) {
                Console.WriteLine(this.Kennung + " erkennt Kennung eigenes Signal.");
            } else {
                Console.WriteLine("{0} empfängt Position von {1}:" + " x={2}, y={3}, h{4}"this.Kennung, kennung, pos.x, pos.y, pos.h);
            } 
        }

        public void Steuern() {
            Program.transponder(Kennung, pos);
        }

    }


    class Program {

        public delegate void TransponderDel(string kennung, Position pos);
        public static TransponderDel transponder;

        public void TransponderTest() {
            Starrflügelflugzeuge flieger1 = new Starrflügelflugzeuge("LH 3000"new Position(30002000100));
            flieger1.Steuern();
            Console.WriteLine(); // Leerzeile
            Starrflügelflugzeuge flieger2 = new Starrflügelflugzeuge("LH 500"new Position(35001500180));
            flieger1.Steuern();
            flieger2.Steuern();
            Console.WriteLine(); // Leerzeile
            Starrflügelflugzeuge flieger3 = new Starrflügelflugzeuge("LH 444"new Position(1730023400780));
            flieger1.Steuern();
            flieger2.Steuern();
            flieger3.Steuern();
            Console.WriteLine(); // Leerzeile
            // Flieger 2 beim Delegate - Objekt abmelden:
            transponder -= flieger2.Transpond;
            flieger1.Steuern();
            flieger3.Steuern();
            Console.ReadLine();
        }

        static void Main(string[] args) {
            Program test = new Program();
            test.TransponderTest();
            Console.ReadLine();
        }
    }


Glaub jetzt versteh ichs, "transponder" ist ja static, also dieses Delegate gibt es nur einmal. Jedes mal wenn ein neues Objekt erzeugt wird und die "Transpond"-Methode initialisiert wird, speichert sich das Delegate also diese Methode.

Also:
flieger1.Transpond;
flieger2.Transpond;
flieger3.Transpond;

Wir dann über Steuern das Delegate "transpond" aufgerufen, werden auch alle Methoden die oben aufgeführt sind, ebenfalls azfgerufen.