【问题标题】:C# Strange Instance of 'System.ArgumentOutOfRangeException''System.ArgumentOutOfRangeException' 的 C# 奇怪实例
【发布时间】:2018-12-19 15:46:51
【问题描述】:

我正在使用 LineSeries 从 Beto Rodriguez 的库 LiveCharts.Wpf 中绘制图表。我将值发送到它绘制并相应更新的图表。 我有一个 SeriesCollection,我根据计数器添加值并删除一些值,例如:

if (_counter > 2 )
{
    SeriesCollection[3].Values[_counter-2] = double.NaN;   
}

因此,如果计数器大于 2,我将值设置为 NaN,即我从图表中删除一个点。

问题是,在随机时间,我得到一个System.ArgumentOutOfRangeException,它说

索引超出范围。必须是非负数且小于集合的大小。

在值被设置为NaN 并且调试器显示计数器等于0 的位置。

很明显,当计数器在这个if (_counter > 2 ) 条件下等于或小于2 时,我不允许执行这段代码,那么这个异常怎么会发生在这个特定的点上呢?

编辑:这个问题不是关于“System.ArgumentOutOfRangeException”是什么,正如在重复问题中所指出的那样,而是关于这个错误是如何发生的,尽管提前检查了它。基本上,由于多线程,_counter 的值被设置为代码中其他地方的意外值,这是主要问题。 SeriesCollection[3] 与异常无关,如果有人这么认为,我建议从 LiveCharts 库本身中查看此数据类型的实际含义。

【问题讨论】:

  • 如果_counter 根本不代表Values 数组的实际大小,它会出现......你为什么不检查SerisCollection[3].Values.Length? (即使这也不是线程安全的,如果这很重要的话)。
  • 这可能是问题 "SeriesCollection[3]" 吗?
  • 如果调试器显示 _counter 为零,那么我的猜测是你的程序是多线程的,另一个线程已经更新了你的 if 和赋值之间的值。
  • 是否有另一个线程改变了_counter?更安全的实现是var i = _counter - 2; if (i >= 0) { SeriesCollection[3].Values[i] = double.NaN; }
  • @PaulF 我不这么认为,那是 LineSeries 的概念,我还有一些其他的 SeriesCollection[x]。

标签: c# wpf exception-handling livecharts


【解决方案1】:

此代码在以下情况下会引发索引超出范围异常:

if (_counter > 2 )
{
    SeriesCollection[3].Values[_counter-2] = double.NaN;   
}
  1. SeriesCollection 中的项目少于 4 个。

  2. SeriesCollection[3].Values 中的项目少于 _counter-1。 (所以如果计数器为 3,Values 集合必须至少有两个值 - 这样_counter-2 将成为第二项。

另外,如果这是一个多线程环境,很可能是另一个线程在条件和赋值之间改变了_counter 的值。为防止这种情况,您需要使用locks:

private object _lock = new Object(); 
lock(_lock)
{
    if (_counter > 2 )
    {
        SeriesCollection[3].Values[_counter-2] = double.NaN;   
    }
}

请注意,您的问题确实建议在多线程环境中工作 -

在值被设置为 NaN 并且调试器显示计数器等于 0 时。

只有当 _counter 的值在条件评估和分配之间发生更改时才会发生这种情况。

【讨论】:

  • 我不同意“SeriesCollection 中的项目少于 4 个”。 ,因为除了例外,它根本不相关。该程序是多线程的,正如 cmets 中所指出的那样,可能只需设置另一个等于 _counter 的变量即可。很抱歉我没有提到程序是多线程的。
  • 我并不是说这是导致异常的原因,我只是将其列为可能的原因 - 但是我从您的问题中引用的句子以及您对我的回答的评论建议问题确实是线程安全。添加锁,你应该没问题。
【解决方案2】:

肯定有另一个线程在检查之间更改_counter 的值

if (_counter > 2)

并在其中使用它

Values[_counter - 2]

更安全的实现只会访问一次:

var i = _counter - 2;

if (i >= 0)
{
    SeriesCollection[3].Values[i] = double.NaN;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-06-26
    • 1970-01-01
    • 1970-01-01
    • 2011-12-19
    • 1970-01-01
    • 1970-01-01
    • 2011-09-13
    • 1970-01-01
    相关资源
    最近更新 更多