Я использую LineSeries для рисования диаграммы из библиотеки LiveCharts.Wpf Бето Родригеса. Я отправляю значения в диаграмму, которую она рисует и обновляет соответственно. У меня есть SeriesCollection, в которую я добавляю значения на основе счетчика, а также удаляю некоторые значения, например:
if (_counter > 2 )
{
SeriesCollection[3].Values[_counter-2] = double.NaN;
}
Поэтому, если значение счетчика больше 2, я устанавливаю значение NaN, то есть стираю точку с диаграммы.
Проблема в том, что в случайное время я получаю System.ArgumentOutOfRangeException, и он говорит
Index was out of range. Must be non-negative and less than the size of the collection.
в точке, где устанавливается значение NaN, и отладчик показывает, что счетчик равен 0.
Очевидно, я не разрешаю выполнять этот код, когда счетчик равен или меньше 2 по этому условию if (_counter > 2 ), так как же это исключение могло произойти в этой конкретной точке?
Обновлено: этот вопрос не о том, что такое «System.ArgumentOutOfRangeException», как указано в повторяющемся вопросе, а о том, как возникла эта ошибка, несмотря на ее предварительную проверку. В основном значение _counter устанавливается на неожиданное значение где-то еще в коде из-за многопоточности, и это была основная проблема. SeriesCollection [3] не имеет ничего общего с исключением, и если кто-то так считает, я предлагаю проверить, что на самом деле означает этот тип данных, из самой библиотеки LiveCharts.
Есть ли вероятность, что это проблема "Коллекция серий [3]"?
Если отладчик показывает, что _counter равен нулю, то я предполагаю, что ваша программа многопоточная, и другой поток обновил значение между вашим if и присвоением.
Может быть, есть еще одна ветка, которая меняет _counter? Более безопасная реализация - var i = _counter - 2; if (i >= 0) { SeriesCollection[3].Values[i] = double.NaN; }.
@PaulF Я так не думаю, это обозначение LineSeries, у меня есть еще несколько SeriesCollection [x].
Проверьте значение _counter - 2, так как оно больше или равно длины вашей коллекции.
См. Мой комментарий об использовании временной переменной, уже сделанный Клеменсом - для отладки вы можете добавить условную точку останова внутри оператора if, чтобы проверить, иногда _counter равен нулю.
@Kensei, который не нужен, поскольку есть условие для проверки того, что, скорее всего, как указали Ганс Килиан или Клеменс, я проверю наличие дополнительных потоков, обращающихся к переменной _counter
Если SeriesCollection[3].Values не содержит значений, вы должны получить исключение ArgumentOutOfRangeException.
Где устанавливается "_прилавок"? Есть ли причина, по которой вы используете переменную, а не «Значения.Длина» (или "Values.Count") напрямую?
@Clemens, пожалуйста, оставьте свой комментарий в качестве ответа, я бы принял его
Возможный дубликат Что такое IndexOutOfRangeException / ArgumentOutOfRangeException и как его исправить?
@Liam это не так, см. Отредактированную версию. Я думаю, вы неправильно поняли, о чем идет речь.
Вы указываете в своей правке, что несмотря на то, что проверил его заранее. где вы это проверяете заранее? Как узнать, что SeriesCollection[3] содержит 3 значения или что SeriesCollection[3].Values[_counter-2] содержит значения Counter-2? Это должен быть дубликат, потому что единственный способ получить эту ошибку - это когда индекс выходит за пределы допустимого диапазона.
Кажется, у вас может быть проблема синхронизации, но вы вообще не указываете это в вопросе?
@Liam Я предлагаю вам изучить SeriesCollection, производный от LiveCharts.Helpers.NoisyCollection <ISeriesView>, который является членом LiveCharts. Во-первых, SeriesCollection [3] не имеет ничего общего с исключением, поскольку он просто обозначает номер строки, которую я рисую на Живом графике. У меня также есть набор SeriexCollection [x], каждый из которых рисует разные линии на моем графике. исключение было вызвано его «Values [i]», где «i» было установлено на отрицательное число. Во-вторых, проверка выполняется «if (_counter> 2)», поэтому индекс в «Values [_counter-2]» никогда не может быть отрицательным.





Этот код генерирует исключение индекса вне диапазона при следующих условиях:
if (_counter > 2 )
{
SeriesCollection[3].Values[_counter-2] = double.NaN;
}
В SeriesCollection меньше 4 элементов.
SeriesCollection[3].Values содержит меньше, чем _counter-1 элементов. (поэтому, если счетчик равен 3, коллекция Values должна иметь как минимум два значения, чтобы _counter-2 был вторым элементом.
Кроме того, если это многопоточная среда, вполне возможно, что другой поток изменил значение _counter между условием и назначением. Чтобы этого не произошло, нужно использовать замки:
private object _lock = new Object();
lock(_lock)
{
if (_counter > 2 )
{
SeriesCollection[3].Values[_counter-2] = double.NaN;
}
}
Обратите внимание, что ваш вопрос предполагает работу в многопоточной среде -
at the point where the value is being set to NaN and the debugger shows that the counter is equal to 0.
Это может произойти только в том случае, если значение _counter было изменено между оценкой условия и присвоением.
Я не согласен с тем, что «SeriesCollection содержит менее 4 элементов». , потому что это вообще не актуально, за исключением. Программа многопоточная, и, возможно, будет работать просто установка другой переменной, равной _counter, как указано в комментариях. Мне жаль, что я не упомянул, что программа многопоточная.
Я не говорю, что это вызвало исключение, я просто перечисляю это как возможную причину - однако предложение, которое я процитировал из вашего вопроса, а также ваш комментарий к моему ответу, предполагают, что проблема действительно связана с потоком безопасность. Добавьте замок, и все будет в порядке.
Конечно, есть еще один поток, который изменяет значение _counter между проверками
if (_counter > 2)
и используя его в
Values[_counter - 2]
Более безопасная реализация будет обращаться к нему только один раз:
var i = _counter - 2;
if (i >= 0)
{
SeriesCollection[3].Values[i] = double.NaN;
}
Что ж, казалось бы, если
_counterпросто не представляет реальный размер массиваValues.... Почему бы вам не проверитьSerisCollection[3].Values.Length? (и даже это не будет потокобезопасным, если это имеет значение).