Как удалить элемент из коллекции, во время перебора этой коллекции 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();
}
}
}