Как удалить элемент из коллекции, во время перебора этой коллекции foreach? - C#
Формулировка задачи:
Прив. Смотрите что. Есть сервер, на нем 2 класса - Server & ClientConnection. При подключении нового клиента в Server создается новый экземпляр класса ClientConnection и добавляется в List<ClientConnection>. При отправке пользователем сообщения на сервер, сервер отсылает его всем остальным пользователям при помощи foreach в классе Server, который в каждом ClientConnection вызывает функцию, которая отправляет сообщение , а в ClientConnection написано - если не удалось отправить сообщение, то вероятно, этот пользователь отключился, а значит мы вызываем метод DeleteClient из класса Server и передаем как параметр текущий класс ClientConnection, а в методе DeleteClient мы удаляем из коллекции List<ClientConnection> класс ClientConnection, который получили как параметр. И возникает исключение из-за того, что мы пытаемся удалить элемент из List<ClientConnection> в то время, когда мы перебираем эту коллекцию foreach'eм в классе Server.
Дайте совет, как правильно оформить удаление класса ClientConnection из коллекции, когда пользователь отключается? Спасибки.
Класс Server:
Класс ClientConnection
ну и main:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Net; using System.Net.Sockets; namespace TestSocketAsyncServer { class Server { private Socket Sock; private SocketAsyncEventArgs AcceptAsyncArgs; private List<ClientConnection> Clients = new List<ClientConnection>(); public Server() { Sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); AcceptAsyncArgs = new SocketAsyncEventArgs(); AcceptAsyncArgs.Completed += AcceptCompleted; } private void AcceptCompleted(object sender, SocketAsyncEventArgs e) { if (e.SocketError == SocketError.Success) { Console.WriteLine("подключился чел"); ClientConnection Client = new ClientConnection(e.AcceptSocket, this); Clients.Add(Client); } e.AcceptSocket = null; AcceptAsync(AcceptAsyncArgs); } private void AcceptAsync(SocketAsyncEventArgs e) { bool willRaiseEvent = Sock.AcceptAsync(e); if (!willRaiseEvent) AcceptCompleted(Sock, e); } public void Start(int Port) { Sock.Bind(new IPEndPoint(IPAddress.Any, Port)); Sock.Listen(50); AcceptAsync(AcceptAsyncArgs); } public void Stop() { Sock.Close(); } public void SendToAll(string data) { Console.WriteLine("number conn = "+Clients.Count); try { foreach (ClientConnection Cl in Clients) { Cl.SendAsync(data); } } catch (Exception ex) { Console.WriteLine(ex.Message); //здесь иссключение вылазиет } } public void DeleteClient(ClientConnection cl) { Clients.Remove(cl); } } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Net.Sockets; namespace TestSocketAsyncServer { class ClientConnection { private static int ClientNumber = 0; private Socket Sock; private SocketAsyncEventArgs SockAsyncEventArgs; private byte[] buff; private Server srv; public ClientConnection(Socket AcceptedSocket, Server srvv) { srv = srvv; ClientNumber++; buff = new byte[1024]; Sock = AcceptedSocket; SockAsyncEventArgs = new SocketAsyncEventArgs(); SockAsyncEventArgs.Completed += SockAsyncEventArgs_Completed; SockAsyncEventArgs.SetBuffer(buff, 0, buff.Length); SockAsyncEventArgs.UserToken = false; ReceiveAsync(SockAsyncEventArgs); } private void SockAsyncEventArgs_Completed(object sender, SocketAsyncEventArgs e) { switch (e.LastOperation) { case SocketAsyncOperation.Receive: ProcessReceive(e); break; case SocketAsyncOperation.Send: ProcessSend(e); break; } } private void ProcessSend(SocketAsyncEventArgs e) { if ((bool)SockAsyncEventArgs.UserToken == false) if (e.SocketError == SocketError.Success) ReceiveAsync(SockAsyncEventArgs); } private void ProcessReceive(SocketAsyncEventArgs e) { if (e.SocketError == SocketError.Success) { SockAsyncEventArgs.UserToken = false; string str = Encoding.UTF8.GetString(e.Buffer, 0, e.BytesTransferred); Console.WriteLine("Incoming msg from #{0}: {1}", ClientNumber, str); srv.SendToAll(str); //SendAsync("You send " + str); } } private void ReceiveAsync(SocketAsyncEventArgs e) { bool willRaiseEvent = Sock.ReceiveAsync(e); e.UserToken = true; if (!willRaiseEvent) ProcessReceive(e); } public void SendAsync(string data) { byte [] buff = Encoding.UTF8.GetBytes(data); SocketAsyncEventArgs e = new SocketAsyncEventArgs(); e.Completed += SockAsyncEventArgs_Completed; e.SetBuffer(buff, 0, buff.Length); try { SendAsync(e); } catch (Exception ex) { Console.WriteLine(ex.Message); } } private void SendAsync(SocketAsyncEventArgs e) { bool willRaiseEvent = Sock.SendAsync(e); if (!willRaiseEvent) { srv.DeleteClient(this); // ProcessSend(e); Console.WriteLine("Connection reset"); } } } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace TestSocketAsyncServer { class Program { static void Main(string[] args) { int Port = 9095; Server srv = new Server(); srv.Start(Port); Console.Read(); srv.Stop(); } } }
Решение задачи: «Как удалить элемент из коллекции, во время перебора этой коллекции foreach?»
textual
Листинг программы
lock (Clients) { foreach (ClientConnection Cl in Clients) { if (Cl.ClientNumber != number) Cl.SendAsync(data); } lock (id) { foreach (ClientConnection c in Clients) { foreach (int i in id) { if (c.GetId() == i) lock (Clients) { Clients.Remove(c); } } id.Clear(); } } }
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д