-3

I am using a LineSeries for drawing a chart from the library LiveCharts.Wpf by Beto Rodriguez. I am sending values to the chart which it draws and updates accordingly. I have a SeriesCollection to which I add the values based on a counter and also remove some values , as for example this :

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

So if the counter equals to something more than 2 , I set the value to NaN, that is I erase a point from the chart.

The problem is, at random times , I get a System.ArgumentOutOfRangeException and it says

Index was out of range. Must be non-negative and less than the size of the collection.

at the point where the value is being set to NaN and the debugger shows that the counter is equal to 0.

Obviously I am not allowing to execute this code when the counter is equal or less than 2 by this if (_counter > 2 ) condition, so how could this exception occur at this particular point?

EDIT : This question is not about what a 'System.ArgumentOutOfRangeException' is, as pointed out in the duplicate question, rather it was about how come this error was occurring in spite of checking for it in advance. Basically the value of _counter is being set to an unexpected value somewhere else in the code due to multi threading and that was the main issue. SeriesCollection[3] has nothing to do with the exception, and if anyone thinks so, I suggest checking out what this data type actually means from the LiveCharts library itself.

Syed Saad
  • 705
  • 5
  • 15
  • 1
    Well it would appear if `_counter` simply does not represent the real size of the `Values` array....Why don't you check `SerisCollection[3].Values.Length`? (and even that won't be thread safe, if that matters). – René Vogt Jul 11 '18 at 14:39
  • 2
    Any possibility this is the problem _"SeriesCollection[3]"_ ? – PaulF Jul 11 '18 at 14:41
  • 2
    If the debugger shows _counter to be zero, then my guess is that your program is multi-threaded and another thread has updated the value between your if and the assignment. – Hans Kilian Jul 11 '18 at 14:41
  • 2
    Is there perhaps another thread that changes `_counter`? A safer implementation would be `var i = _counter - 2; if (i >= 0) { SeriesCollection[3].Values[i] = double.NaN; }` – Clemens Jul 11 '18 at 14:41
  • @PaulF I dont think so, that is the LineSeries denotion, I have some other SeriesCollection[x] as well. – Syed Saad Jul 11 '18 at 14:42
  • Check `_counter - 2` value, as it would be greater or equal than your collection length – Kaitiff Jul 11 '18 at 14:45
  • See my comment of using temporary variable has already been made by Clemens - for debugging you could add a conditional breakpoint inside the if statement to check if _counter sometimes is zero. – PaulF Jul 11 '18 at 14:45
  • @Kensei that is not needed,as theres a condition to check that, most probably as Hans Kilian or Clemens pointed out, I will check for additional threads accessing the _counter variable – Syed Saad Jul 11 '18 at 14:49
  • If `SeriesCollection[3].Values` contains no values, you should get that ArgumentOutOfRangeException exception – Zohar Peled Jul 11 '18 at 14:52
  • Where does _"_counter"_ get set? Is there any reason you are using a variable rather than _"Values.Length"_ (or _"Values.Count"_) directly? – PaulF Jul 11 '18 at 14:56
  • @Clemens please post your comment as an answer, I would accept it – Syed Saad Jul 11 '18 at 15:18
  • Possible duplicate of [What is an IndexOutOfRangeException / ArgumentOutOfRangeException and how do I fix it?](https://stackoverflow.com/questions/20940979/what-is-an-indexoutofrangeexception-argumentoutofrangeexception-and-how-do-i-f) – Liam Jul 11 '18 at 15:37
  • @Liam it is not, see the edited version. I think you misunderstood what the question is about. – Syed Saad Jul 11 '18 at 15:40
  • You state in your edit that *in spite of checking for it in advance.* where do you check this in advance? How do you know that `SeriesCollection[3]` contains 3 values or that `SeriesCollection[3].Values[_counter-2]` contains `Counter-2` values? This must be a duplicate because the only way you get that error is when the index is out of range. – Liam Jul 11 '18 at 15:55
  • Seems you might have a [synchronisation issue](https://stackoverflow.com/questions/51288236/c-sharp-strange-instance-of-system-argumentoutofrangeexception?noredirect=1#comment89555801_51288834), but you don't state this in the question at all? – Liam Jul 11 '18 at 15:58
  • @Liam i suggest you look into SeriesCollection that is derived from LiveCharts.Helpers.NoisyCollection which is a member LiveCharts.Firstly, SeriesCollection[3] has nothing to do with the exception, as It merely denotes the line number I am drawing on the Live Chart. I have a bunch of SeriexCollection[x] as well, all which draws different lines on my chart. the thing which was throwing the exception is its 'Values[i]', where 'i' was being set to a negative number. Secondly, the check is 'if (_counter > 2 )' , therefore the index in 'Values[_counter-2]' can never be negative. – Syed Saad Jul 11 '18 at 16:18

2 Answers2

2

This code with throw an index out of range exception under the following conditions:

if (_counter > 2 )
{
    SeriesCollection[3].Values[_counter-2] = double.NaN;   
}
  1. SeriesCollection has less than 4 items in it.

  2. SeriesCollection[3].Values has less than _counter-1 items in it. (so if counter is 3, the Values collection must have at least two values - so that _counter-2 will be the second item.

Also, if this is a multi threaded environment, it's quite possible that a different thread have changed the value of _counter between the condition and the assignment. To prevent this you need to use locks:

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

Please note that your question does suggest working in a multi threaded environment -

at the point where the value is being set to NaN and the debugger shows that the counter is equal to 0.

This can only happen if the value of _counter was changed between the evaluation of the condition and the assignment.

Zohar Peled
  • 79,642
  • 10
  • 69
  • 121
  • I dont agree with "SeriesCollection has less than 4 items in it." , because its not relevant at all with the exception. The program is multithreaded and maybe just setting another variable equal to _counter will work, as pointed out in the comments. I am sorry that I didn't mention the program is multithreaded. – Syed Saad Jul 11 '18 at 15:14
  • 1
    I'm not saying this is what caused the exception, I'm just listing it as a possible reason - however the sentence I've quoted from your question as well as your comment to my answer suggest that the problem is, indeed, thread safety. Add the lock and you should be fine. – Zohar Peled Jul 11 '18 at 15:17
0

There is certainly another thread that changes the value of _counter between checking

if (_counter > 2)

and using it in

Values[_counter - 2]

A safer implementation would access it only once:

var i = _counter - 2;

if (i >= 0)
{
    SeriesCollection[3].Values[i] = double.NaN;
}
Clemens
  • 123,504
  • 12
  • 155
  • 268