为什么有时我会得到异常indexOutOfRange?

时间:2015-07-15 20:10:50

标签: c# .net winforms

这是一个计时器刻度事件,我正在获取每个进程内存使用情况。 在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'类型的异常   Automation.exe但未在用户代码中处理

     

其他信息:索引超出了数组的范围

     

System.IndexOutOfRangeException未被用户代码

处理

它只发生过一次或多次。大部分时间都没有显示异常。

当我把鼠标放在proclist上然后在Count上我看到:

  

Count =由于之前的功能而禁用了功能评估   评估超时。您必须继续执行以重新启用功能   评价。

计时器的间隔设置为1000毫秒。

不确定是什么意思我必须继续执行以重新启用功能评估。以及如何解决它。 为什么有时它确实会成为例外而在大多数情况下都没有?

我根据Dan的回答更改了我的代码,但现在又在另一个地方获得了异常。 这是新代码:

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.dll中出现'System.InvalidOperationException'类型的异常,但未在用户代码中处理

其他信息:实例'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: 

3 个答案:

答案 0 :(得分:2)

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

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

你在这里做的是

  1. 获取所有流程的列表
  2. 获取与第一个列表中的某个进程同名的进程列表
  3. 获取第二个列表中第一个进程的名称
  4. 忽略这里的冗余,问题是时间问题。

    假设您正在运行进程foo.exe。该过程显示在步骤1的列表中。如果该流程应在步骤1和2之间终止,则foo.exe的步骤2中的列表将为空。列表为空时调用processes[0]将抛出您已经看过的异常。

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

答案 1 :(得分:0)

可能没有具有您要查找的名称的进程。发生这种情况时,processes的长度为0,并且没有有效的索引。因此,无论您在括号中输入什么数字,都会获得IndexOutOfRangeException

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

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

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

答案 2 :(得分:0)

在循环期间,如果进程结束,将抛出异常...