инициировать событие из AsyncCallback в C # - PullRequest
0 голосов
/ 18 ноября 2010

Мой вопрос касается событий и того, где я запускаю события в моем классе.Этот класс оборачивает мою функциональность TCP, и я использую TcpListener для достижения этой цели.Я понимаю, что некоторые вещи TCP могут отсутствовать в следующем примере, но я хочу сделать вещи максимально простыми:

c # 2.0 sample

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
   }
}

Я думаю, мойВопрос в том, что, не нарушая эту модель слишком много, что имеет больше смысла?Кроме того, если у кого-то есть лучшее, более элегантное решение, оно приветствуется.

Теория

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.";
   }
}

1 Ответ

0 голосов
/ 18 ноября 2010

Хотя вы не опубликовали код для MyTcpClass2, я почти уверен, что вижу, к чему вы клоните.

Нет, я бы так не поступил. Потому что, например, если что-то еще нужно связать с этим событием одновременно, вы заставите его работать в другом потоке.

Короче говоря, метод, который получает событие, должен отвечать за выполнение любого кода, который ему необходим, в любом потоке, в котором он нуждается. Механизм, который вызывает событие, должен быть полностью забыт о любых странных вещах, которые требуются получателю. Помимо усложнения сценария связывания нескольких событий, он перемещает логику межпотокового вызова в класс, к которому он не принадлежит. Класс MyTcpClass должен быть ориентирован на обработку вопросов клиент / сервер TCP, а не на работу с потоками Winforms.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...