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

    }
}
ну и main:
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();
                        }
                    }
 
                }

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

15   голосов , оценка 3.933 из 5
Похожие ответы