c#修改了无效操作异常集合

本文关键字:异常 集合 操作 无效 修改 | 更新日期: 2023-09-27 18:13:53

你好,我正试图实现Facebook的朋友跟踪器,可以跟踪谁是在线的,谁是使用Selenium WebDriver离线。

一切正常,除了当用户脱机并将其从集合中移除时,它会抛出异常。

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using System.Threading;
using OpenQA.Selenium;
using OpenQA.Selenium.Edge;
using OpenQA.Selenium.Support.Events;
using OpenQA.Selenium.Support.UI;
namespace FacebookFriendTracker
{
    public delegate void StatusChangedEventHandler(object source, StatusChangedEventArgs e);
    public class Watcher
    {
        private readonly IWebDriver _driver;
        private HashSet<User> _tempUserOnline = new HashSet<User>();
        public event StatusChangedEventHandler StatusChanged;
        private bool run;
        public Watcher()
        {
            //UsersOnline = new HashSet<User>();
            _driver = new EdgeDriver();
            _driver.Navigate().GoToUrl("https://mbasic.facebook.com");
            var wait = new WebDriverWait(_driver, TimeSpan.FromSeconds(20));
            wait.Until(ExpectedConditions.ElementExists(By.PartialLinkText("Chat")));
            var element = _driver.FindElement(By.PartialLinkText("Chat"));
            element.Click();
            run = false;
        }
        public void Tracker()
        {
            Thread.Sleep(5000);
            //_usersOnline = _driver.FindElements(By.XPath(".//a[contains(@href,'fbid')]"));
            var usersOnline = new HashSet<User>();
            foreach (var userOnline in _driver.FindElements(By.XPath(".//a[contains(@href,'fbid')]")))
            {
                var extracedAttributeValue = userOnline.GetAttribute("href");
                var regex = new Regex(@"'d+");
                var id = long.Parse(regex.Match(extracedAttributeValue).Value);
                var fullName = userOnline.Text;
                usersOnline.Add(new User() {FullName = fullName, Id = id});
            }
            while (true)
            {
                Thread.Sleep(5000);
                _driver.Navigate().Refresh();
                var newUsersOnline = new HashSet<User>();
                foreach (var user in _driver.FindElements(By.XPath(".//a[contains(@href,'fbid')]")))
                {
                    var attirbute = user.GetAttribute("href");
                    var reg = new Regex(@"'d+");
                    var newId = long.Parse(reg.Match(attirbute).Value);
                    var newFullName = user.Text;
                    newUsersOnline.Add(new User() { FullName = newFullName, Id = newId });
                }
                _tempUserOnline = usersOnline;
                foreach (var usrOnline in newUsersOnline.Except(_tempUserOnline))
                {
                    OnStatusChanged(this , new StatusChangedEventArgs() {User = usrOnline,Status = Status.Online});
                    _tempUserOnline.Add(usrOnline);
                }
                // Here it throws and exception if the the user goes offline 
                foreach (var usroffline in usersOnline.Except(newUsersOnline))
                {
                    OnStatusChanged(this, new StatusChangedEventArgs() { User = usroffline, Status = Status.Offline });
                    _tempUserOnline.Remove(usroffline);
                }
            }
        }
        protected virtual void OnStatusChanged(object source, StatusChangedEventArgs e)
        {
            if (StatusChanged !=null)
                OnStatusChanged(source,e);
            else
            {
                Console.WriteLine("User: {0} is {1} ",e.User.FullName,e.Status);
            }
        }
    }
}

c#修改了无效操作异常集合

在模拟过程中不能修改该集合。一个常见的修复方法是ToList():

foreach (var usroffline in usersOnline.Except(newUsersOnline).ToList())
{
       OnStatusChanged(this, new StatusChangedEventArgs() { User = usroffline, Status = Status.Offline });
       _tempUserOnline.Remove(usroffline);
}

问题是,当你使用foreach循环遍历它时,你不能修改集合。

这里,您将_tempUserOnline设置为指向与usersOnline相同的对象:

_tempUserOnline = usersOnline;

再往下,你有这个循环,它修改了_tempUserOnline,从而也修改了usersOnline,因为它们指向同一个对象。由于您正在循环usersOnline(实际上也是_tempUserOnline),因此当您执行_tempUserOnline.Remove(usroffline)时,您会得到错误。

foreach (var usroffline in usersOnline.Except(newUsersOnline))
{
    OnStatusChanged(this, new StatusChangedEventArgs() { User = usroffline, Status = Status.Offline });
    _tempUserOnline.Remove(usroffline);
}

您是否打算将复制 usersOnlinetempUserOnline ?如果是这样,您应该使用.CopyTo()或类似的东西来进行实际的复制:

User[] _tempUserOnline = new User[usersOnline.Count - 1];
usersOnline.CopyTo(_tempUserOnline);