2016-10-20 18 views
-3

こんにちは、私はFacebook友人トラッカーを実装しようとしています。これはSelenium WebDriverを使ってオンラインの人とオフラインの人を追跡できます。無効な操作例外コレクションが変更されました。C#

ユーザーがオフラインになって例外をスローするコレクションから削除する場合を除いて、すべてが正常に機能します。

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

} 
+0

このコードは何を示していますか?例外がどこで発生しているのかを指摘できますか?どの行? –

+0

@ rory.ap例外がスローされた場所を示すコードがコメントにあります –

+1

反復処理中のコレクションを変更しようとしています。それは許可されていません。 –

答えて

2

emuerationが進行している間は、そのコレクションを変更することはできません。一般的な修正は、それをToList()することです:

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

問題は、あなたがforeachループでそれを反復している間、あなたがコレクションを変更することができないということです。ここで

、あなたがusersOnlineと同じオブジェクトを指すように_tempUserOnlineを設定している:

_tempUserOnline = usersOnline; 

その後さらに下に、あなたは彼らが同じオブジェクトを指しているので、これもusersOnlineを変更、_tempUserOnlineを修正し、このループを、持っています。 usersOnline(と実質的には_tempUserOnlineも)ループしているので、_tempUserOnline.Remove(usroffline)を実行するとエラーが発生します。

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

} 

あなたはtempUserOnlineコピーusersOnlineにいきましたか?その場合は、.CopyTo()または同等のものを使用して実際のコピーを作成してください。

User[] _tempUserOnline = new User[usersOnline.Count - 1]; 
usersOnline.CopyTo(_tempUserOnline); 
関連する問題