5

我的代码:

public void CPUStats()
{
    var cpuCounter = new PerformanceCounter("Processor", "% Processor Time", 
                                                                     "_Total");
    var ramCounter = new PerformanceCounter("Memory", "Available MBytes");
    ramCounter.NextValue();
    cpuCounter.NextValue();
    System.Threading.Thread.Sleep(1000);
    string cpusage = cpuCounter.NextValue().ToString();
    string ramusage = ramCounter.NextValue().ToString();

    //Occurs here v
    try
    {
        //exception thrown here v
        cpuLabel.Invoke((MethodInvoker)(() => cpuLabel.Text = "CPU: " + 
                                   cpusage.Remove(cpusage.IndexOf('.')) + "%"));
    }
    catch(ArgumentOutOfRangeException)
    {
        cpuLabel.Invoke((MethodInvoker)(() => cpuLabel.Text = "CPU: " + 
                                                                 cpusage + "%"));
    }

    ramLabel.Invoke((MethodInvoker)(() => ramLabel.Text = "Free RAM: " + 
                                                             ramusage + "mb"));
}

有时我的应用程序会在 cpuLabel 调用处停止并在我的代码中处理和修复它时抛出“ArgumentOutOfRangeException”。我尝试增加激活 CPUStats() 的线程的计时器,但无济于事。

为什么会发生这种情况?

4

3 回答 3

2

问题是由以下代码引起的:

cpusage.Remove(cpusage.IndexOf('.')

您需要确保 cpusage 有长度并包含“。” 在尝试调用 .Remove 之前。

您可以通过运行一个简单的应用程序测试来证明这一点:

        var cpuusage = "0";

        System.Diagnostics.Debug.WriteLine(cpuusage.Remove(cpuusage.IndexOf('.')));

这将引发 ArgumentOutOfRangeException 异常。

如果将代码修改为:

        var cpuusageforlabel = "CPU: ";
        if (!string.IsNullOrEmpty(cpuusage)) {
            var index = cpuusage.IndexOf('.');
            if (index != -1) {
                cpuusageforlabel += cpuusage.Remove(index);
            } else {
                cpuusageforlabel += cpuusage;
            }
        } else {
            cpuusageforlabel += "0";
        }
        cpuusageforlabel += "%";

   cpuLabel.Invoke((MethodInvoker)(() => cpuLabel.Text = cpuusageforlabel));

您可以解决异常,并且不必捕获参数超出范围的异常。

于 2013-11-01T00:20:15.717 回答
2

更新:

抱歉,我应该更仔细地阅读您的代码。您try-catch包装的委托调用可能不在 thread 的当前上下文中。我认为你想要做的应该是:

public void CPUStats() {
    var cpuCounter= .. 

    ... 

    MethodInvoker m=() => {
        try {
            cpuLabel.Text="CPU: "+cpusage.Remove(cpusage.IndexOf('.'))+"%";
        }
        catch(ArgumentOutOfRangeException) {
            cpuLabel.Text="CPU: "+cpusage+"%";
        }
    };

    cpuLabel.Invoke(m);

    ... 
}

看看SynchronizationContextControl.InvokeRequired

同样,try-catch如果有更好的方法来检查可能的错误,请避免。


@competent_tech 的回答很好,但我想补充一点。

在某些情况下,try-catch块仍然会抛出:

  1. 你没有捕捉到它抛出的确切异常

  2. 处理程序重新抛出原始异常

  3. 处理程序导致另一个异常

在您的情况下,它命中了catch块并且没有重新抛出原始块,也就是说,它遇到了第三种情况:处理程序导致另一个异常。

如果你能解决问题导致异常并避免它,那么就不要这样设计它。

Lippert 先生写了一篇关于异常的好文章,您可能想看看:

http://ericlippert.com/2008/09/10/vexing-exceptions/

于 2013-11-01T01:06:02.770 回答
0

最可能的原因是cpusagenull 或 empty 或没有. 所以当你得到异常并再次尝试使用相同的变量时,你会得到第二个异常。

使用前请检查cpusage,不要使用catch您正在使用的方式。

于 2013-11-01T00:20:30.493 回答