2010-11-18 5 views
0

Meine Frage beinhaltet Ereignisse und wo ich die Ereignisse in meiner Klasse auslöst. Diese Klasse umschließt meine TCP-Funktionalität und ich verwende TcpListener, um dies zu erreichen. Ich weiß, einige TCP Sachen aus dem folgenden Beispiel fehlt möglicherweise, aber ich möchte die Dinge so einfach wie möglich machen:trigger event von einem AsyncCallback in C#

C# 2.0 Probe

class MyTcpClass 
{ 
    public delegate void ClientConnectHandler(Socket client, int clientNum); 

    public event ClientConnectHandler ClientConnect; 

    private Socket wellKnownSocket; 
    private Socket[] clientSockets = new Socket[MAX_CLIENTS]; 
    private int numConnected = 0; 

    private void OnClientConnect(Socket client, int clientNum) 
    { 
     if (ClientConnect != null) 
     ClientConnect(client, clientNum); 
    } 

    public void StartListening() 
    { 
     //initialize wellKnownSocket 
     //... 
     wellKnownSocket.BeginAccept(new AsyncCallback(internal_clientConnect); 
    } 

    public void internal_clientConnect(IAsyncResult ar) 
    { 
     //Add client socket to clientSocket[numConnected] 
     //numConnected++; 
     //... 
     wellKnownSocket.EndAccept(ar); 

     OnClientConnect(clientSocket[numConnected], numConnected);   
     //error: event happens on different thread!! 
    } 
} 

class MainForm 
{ 
    void Button_click() 
    { 
     MyTcpClass mtc = new MyTcpClass(); 
     mtc.ClientConnect += mtc_ClientConnected; 
    } 

    void mtc_clientConnected(Socket client, int clientNum) 
    { 
     ActivityListBox.Items.Add("Client #" + clientNum.ToString() + " connected."); 
     //exception: cannot modify control on seperate thread 
    } 
} 

Ich denke, meine Frage ist, ohne dieses Muster zu brechen viel, was macht mehr Sinn? Auch wenn jemand eine bessere elegante Lösung hat, sind sie willkommen.

Theorie

class MainForm 
{ 
    public MainForm() 
    { 
     MyTcpClass mtc = new MyTcpClass(); 
     MyTcpClass2 mtc2 = new MyTcpClass2(this); 
     //this version holds a Form handle to invoke the event 

     mtc.ClientConnect += mtc_uglyClientConnect; 
     mtc2.ClientConnect += mtc2_smartClientConnect; 
    } 

    //This event is being called in the AsyncCallback of MyTcpClass 
    //the main form handles invoking the control, I want to avoid this 
    void mtc_uglyClientConnect(Socket s, int n) 
    { 
     if (mycontrol.InvokeRequired) 
     { 
     //call begininvoke to update mycontrol 
     } 
     else 
     { 
     mycontrol.text = "Client " + n.ToString() + " connected."; 
     } 
    } 

    //This is slightly cleaner, as it is triggered in MyTcpClass2 by using its 
    //passed in Form handle's BeginInvoke to trigger the event on its own thread. 
    //However, I also want to avoid this because referencing a form in a seperate class 
    //while having it (the main form) observe events in the class as well seems... bad 
    void mtc2_smartClientConnect(Socket s, int n) 
    { 
     mycontrol.text = "Client " + n.ToString() + " connected."; 
    } 
} 

Antwort

0

Während Sie den Code für MyTcpClass2 keine Beiträge habe, bin ich ziemlich sicher, dass ich sehe, was auf Sie bekommen.

Nein, ich würde es nicht auf die zweite Art tun. Zum Beispiel, wenn irgendetwas anderes gleichzeitig an dieses Ereignis gebunden werden muss, erzwingen Sie, dass es in einem anderen Thread ausgeführt wird.

Kurz gesagt, sollte die Methode, die das Ereignis empfängt, dafür verantwortlich sein, den Code auszuführen, der für den jeweiligen Thread benötigt wird. Der Mechanismus, der das Ereignis auslöst, sollte sich keinerlei merkwürdiges Threading-Material merken, das der Empfänger benötigt. Abgesehen davon, dass das Szenario zum Binden mehrerer Ereignisse kompliziert ist, verschiebt es die Logik des cross-thread-Aufrufs in eine Klasse, in die es nicht gehört. Die Klasse MyTcpClass sollte sich auf die Behandlung von TCP-Client/Server-Angelegenheiten konzentrieren und nicht mit Winforms-Threads herumärgern.

+0

Also schlagen Sie das erste Beispiel vor, wo ich Zugriff auf Winform-Steuerelement Sachen in der Event-Handler in MainForm mit Aufruf? Mir ist klar, dass MyTcpClass sich nicht bewusst ist, auf welchem ​​Thread es läuft, aber MyTcpClass "Has An" asynchrone Callback-Beziehung mit Client-Verbindung. Am liebsten würde ich das Ereignis im Thread auslösen (egal zu welchem ​​Thread), in dem MyTcpClass erstellt wurde. Ich sehe Ihren Standpunkt und stimme ihm zu, jedoch modelliert Microsoft selbst ein ähnliches Ereignis mit seinem "Hintergrundarbeiter" mit seinem progresschanged-Ereignis. –

+0

@Tom: Das Problem ist, dass dieses Threading-Modell ziemlich spezifisch für Winforms ist - Sie können möglicherweise nicht einmal den Event-Handler für den Thread aufrufen, auf dem die Klasse erstellt wurde! (Was ist, wenn der Thread beendet wurde?) – cdhowie