根据计时器引发更新集合'集合已修改;枚举操作可能无法执行." [英] Update collection based on timer throws 'Collection was modified; enumeration operation may not execute.'

查看:58
本文介绍了根据计时器引发更新集合'集合已修改;枚举操作可能无法执行."的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Reactive Extensions和ReactiveUI定期更新 Process 对象的集合.

I'm using Reactive Extensions and ReactiveUI to update a collection of Process objects periodically.

选中复选框后,将填充绑定到DataGrid的属性Processes,并设置计时器以每200ms更新所有进程.退出的进程将被删除.

When a checkbox is checked the property Processes, which is bound to a DataGrid, is filled and a timer is set to update every 200ms all processes. Processes that have exited are removed.

集合已修改;枚举操作可能无法执行.有时在进行foreach时会引发异常.我不明白,因为我没有在迭代时删除或向集合中添加对象(只需设置 ProcessModel 的属性)

The Collection was modified; enumeration operation may not execute. exception is sometimes thrown when doing a foreach. I don't understand, because I am not removing or adding objects to the collection when iterating (just setting a property of the ProcessModel)

计时器还会等到一切完成后再触发吗?

Also does the timer wait until everything is completed before firing again?

ViewModel

private ReactiveList<IProcessModel> _processes = new ReactiveList<IProcessModel>() { ChangeTrackingEnabled = true };
public ReactiveList<IProcessModel> Processes { get { return _processes; } }

IDisposable timer;

private void DoShowProcesses(bool checkboxChecked)
{
    Processes.Clear();
    if (checkboxChecked)
    {
        //checkbox checked
        lock (Processes)
            Processes.AddRange(_monitorService.GetProcesses());
        timer = Observable.Timer(TimeSpan.FromMilliseconds(200.0))
            .Select(x =>
        {
            lock (Processes)
            {
                foreach (var process in Processes) //throws the 'Collection was modified; enumeration operation may not execute.'
                    process.UpdateMemory(); 

                return Processes.Where(p => p.ProcessObject.HasExited).ToList();
            }
        }).
        ObserveOnDispatcher()
        .Subscribe(processesExited =>
        {
            if (processesExited.Count() > 0)
            {
                lock (Processes)
                    Processes.RemoveAll(processesExited); //remove all processes that have exited
            }

        });
    }
    else
    {
        if (timer != null)
            timer.Dispose();
    }
}

ProcessModel

public class ProcessModel : ProcessModelBase, IProcessModel
{

    public ProcessModel(Process process)
    {
        ProcessObject = process;

    }

    public void UpdateMemory()
    {
        try
        {
            if (!ProcessObject.HasExited)
            {
                long mem = ProcessObject.PagedMemorySize64;
                ProcessObject.Refresh();
                if (mem != ProcessObject.PagedMemorySize64)
                    OnPropertyChanged(nameof(ProcessObject));
            }
        }
        catch (Exception)
        {
            //log it
        }
    }

推荐答案

最好发布一个最小,完整,可验证的示例为您提供帮助.无法按书面要求进行调试或测试.

It is best to post a minimal, complete, verifiable example to help you. This isn't possible to debug or test as written.

作为猜测,我假设您有某种处理程序,该处理程序是由 OnPropertyChanged(nameof(ProcessObject)); 调用触发的.此处理程序可能会从可枚举中删除并可能重新添加了该对象.要进行测试,您可以分离处理程序,或删除调用,看看是否仍然发生异常.

As a guess, I would assume you have some sort of handler which is being triggered by the OnPropertyChanged(nameof(ProcessObject)); call. This handler probably removes and possibly re-adds the object from the enumerable. To test, you can detach the handler, or remove the call and see if the exception still occurs.

这篇关于根据计时器引发更新集合'集合已修改;枚举操作可能无法执行."的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆