为什么有时我得到异常indexoutorange

本文关键字:异常 indexoutorange 为什么 | 更新日期: 2023-09-27 18:03:06

这是一个计时器滴答事件里面我得到每个进程的内存使用情况。在95%的时间里,甚至更多,它工作得很好,我试了大约20次运行我的程序,直到异常抛出。

在表单的顶部:

System.Timers.Timer aTimer = new System.Timers.Timer();

在构造函数中:

aTimer.Elapsed += new System.Timers.ElapsedEventHandler(OnTimedEvent);
aTimer.Interval = 1000;

计时器经过的事件:

Image ima = null;
        private void OnTimedEvent(object source, System.Timers.ElapsedEventArgs e)
        {
            List<MyProgress> prog = new List<MyProgress>();
            prog = new List<MyProgress>();
            DoubleBufferedd(dataGridView1, true);
            procList = Process.GetProcesses().ToList();
            for (int i = 0; i < procList.Count; i++)
            {
                Process[] processes = Process.GetProcessesByName(procList[i].ProcessName);
                PerformanceCounter performanceCounter = new PerformanceCounter();
                performanceCounter.CategoryName = "Process";
                performanceCounter.CounterName = "Working Set - Private";
                performanceCounter.InstanceName = processes[0].ProcessName;
                try
                {
                    var icon = Icon.ExtractAssociatedIcon(processes[0].MainModule.FileName);
                    ima = icon.ToBitmap();
                    ima = resizeImage(ima, new Size(25, 25));
                    ima = (Image)(new Bitmap(ima, new Size(25, 25)));
                }
                catch
                {
                }
                prog.Add(new MyProgress { Id = procList[i].Id, Progress = ((uint)performanceCounter.NextValue() / 1024).ToString("N0"), ProcImage = ima, ProcessName = procList[i].ProcessName });

            }
            BeginInvoke((Action)(() =>
            {
            List<MyProgress> list = prog;//new List<MyProgress>();

                foreach (MyProgress p in list)
                {
                    DataGridViewRow row;
                    if (!processRows.TryGetValue(p.Id, out row))
                    {
                        int index = dataGridView1.Rows.Add(p.ProcImage, p.ProcessName, null, p.Progress);
                        row = dataGridView1.Rows[index];
                        processRows.Add(p.Id, row);
                    }
                    else
                    {
                        row.Cells[3].Value = p.Progress;
                    }
                }
                foreach (int id in processRows.Keys.Except(list.Select(p => p.Id)).ToArray())
                {
                    dataGridView1.Rows.Remove(processRows[id]);
                    processRows.Remove(id);
                }
            }));
        }

当异常发生时,它就行了:

 performanceCounter.InstanceName = processes[0].ProcessName;

类型为'System '的异常。IndexOutOfRangeException'发生在自动化。exe,但未在用户代码中处理

附加信息:索引在数组边界之外

系统。用户代码未处理IndexOutOfRangeException

而且它只发生一次到多次。大多数情况下,异常不显示。

当我把鼠标放在光标上,然后在计数上,我看到:

Count =由于前一个函数而禁用函数求值评估超时。您必须继续执行以重新启用功能评估。

设置定时器间隔1000ms。

不确定这意味着什么,我必须继续执行以重新启用函数求值。以及如何修复它。为什么有时会有例外,而大多数情况下没有?

我根据丹的回答改变了我的代码,但现在在另一个地方得到异常。这是新的代码:

Image ima = null;
        private void OnTimedEvent(object source, System.Timers.ElapsedEventArgs e)
        {
            List<MyProgress> prog = new List<MyProgress>();
            prog = new List<MyProgress>();
            DoubleBufferedd(dataGridView1, true);
            procList = Process.GetProcesses().ToList();
            for (int i = 0; i < procList.Count; i++)
            {
                                PerformanceCounter performanceCounter = new PerformanceCounter();
                performanceCounter.CategoryName = "Process";
                performanceCounter.CounterName = "Working Set - Private";//"Working Set";
                performanceCounter.InstanceName = procList[i].ProcessName;
                try
                {
                    var icon = Icon.ExtractAssociatedIcon(procList[i].MainModule.FileName);
                    ima = icon.ToBitmap();
                    ima = resizeImage(ima, new Size(25, 25));
                    ima = (Image)(new Bitmap(ima, new Size(25, 25)));
                }
                catch
                {
                }
                prog.Add(new MyProgress { Id = procList[i].Id, Progress = ((uint)performanceCounter.NextValue() / 1024).ToString("N0"), ProcImage = ima, ProcessName = procList[i].ProcessName });

            }
            BeginInvoke((Action)(() =>
            {
            List<MyProgress> list = prog;

                foreach (MyProgress p in list)
                {
                    DataGridViewRow row;
                    if (!processRows.TryGetValue(p.Id, out row))
                    {
                                                int index = dataGridView1.Rows.Add(p.ProcImage, p.ProcessName, null, p.Progress);
                        row = dataGridView1.Rows[index];
                        processRows.Add(p.Id, row);
                    }
                    else
                    {
                        row.Cells[3].Value = p.Progress;
                    }
                }
                foreach (int id in processRows.Keys.Except(list.Select(p => p.Id)).ToArray())
                {
                    dataGridView1.Rows.Remove(processRows[id]);
                    processRows.Remove(id);
                }
            }));
        }

我不再使用Process[]进程了。

并将这两行改为使用procList:

这一行我使用procList[i]

performanceCounter.InstanceName = procList[i].ProcessName;

这一行我使用procList[i]

var icon = Icon.ExtractAssociatedIcon(procList[i].MainModule.FileName);

但是现在我得到了异常:

prog.Add(new MyProgress { Id = procList[i].Id, Progress = ((uint)performanceCounter.NextValue() / 1024).ToString("N0"), ProcImage = ima, ProcessName = procList[i].ProcessName });

InvalidOperationException

类型为'System '的异常。InvalidOperationException'在System.dll中发生,但未在用户代码中处理

附加信息:实例'SearchFilterHost'在指定的类别中不存在。

System.InvalidOperationException was unhandled by user code
  HResult=-2146233079
  Message=Instance 'SearchFilterHost' does not exist in the specified Category.
  Source=System
  StackTrace:
       at System.Diagnostics.CounterDefinitionSample.GetInstanceValue(String instanceName)
       at System.Diagnostics.PerformanceCounter.NextSample()
       at System.Diagnostics.PerformanceCounter.NextValue()
       at Automation.Form1.OnTimedEvent(Object source, ElapsedEventArgs e) in d:'C-Sharp'Automation'Automation'Automation'Form1.cs:line 805
       at System.Timers.Timer.MyTimerCallback(Object state)
  InnerException: 

为什么有时我得到异常indexoutorange

下面是与您的问题相关的三行重要代码:

procList = Process.GetProcesses().ToList();
Process[] processes = Process.GetProcessesByName(procList[i].ProcessName);
performanceCounter.InstanceName = processes[0].ProcessName;

你在这里做的是

  1. 获取所有进程的列表
  2. 获取与第一个列表中进程名称相同的进程列表
  3. 获取第二个列表中第一个进程的名称

忽略这里的冗余,问题是时间问题。

假设您有一个进程foo.exe正在运行。这个过程出现在步骤1的列表中。如果该过程在步骤1和步骤2之间终止,则步骤2中foo.exe的列表将为空。当列表为空时调用processes[0]将抛出您所看到的异常。

为了避免这种情况,我建议您完全避免步骤2:您已经检索了所有流程的信息,因此使用您已经拥有的数据。这样做的好处可能是加快代码的速度!

可能没有进程具有您正在查找的名称。当这种情况发生时,processes的长度将为0,并且没有有效的指标。所以不管你在括号里输入什么数字,你都会得到一个IndexOutOfRangeException

要解决这个问题,您应该确保在使用processes数组之前存在匹配进程:

//...
Process[] processes = Process.GetProcessesByName(procList[i].ProcessName);
if (processes.Length > 0) {
    // ...
    performanceCounter.InstanceName = processes[0].ProcessName;

还有其他一些方法可以实现这个目标,但这应该为您指明了正确的方向。

在循环过程中,如果进程结束,将抛出异常…