0

I'm new to C# and what I want to do here is add a conditional to return an empty array if the loop that I have set for my DataPoints API response variable is out of range.

Right now it throws an exception but what I want it to do is instead of throwing the exception just return an empty array in the DataPoints API response. How would I do that?

exception

"Index was out of range. Must be non-negative and less than the size of the collection.\r\nParameter name: index""

code sample

public void BuildDataPoints()
{
    // Create WspViewList from ViewData
    WspViewList dataPointBuilder = new WspViewList(ViewData);

    List<DataPointAPI> dataset = new List<DataPointAPI>();

    WspViewCol _labelCol = null;

    List<WspViewCol> yAxisCols = new List<WspViewCol>();


    //Iterate through the view's columns to find special chart columns
    foreach (WspViewCol col in dataPointBuilder._cols)
    {
        if (col._baseCol.DbrViewCol.YAxis)
            yAxisCols.Add(col);

        if (col._baseCol.DbrViewCol.XAxis)
            _labelCol = col;
    }

    var DataPoints = new DataPoints();
    // Generate DataPoints (or something similar) from the newly constructed WspViewList.
    foreach (WspViewRow row in dataPointBuilder)
    {

        var dataPointList = row.OriginalData.TrimStart('[').TrimEnd(']').Split(',').ToList();

        for (var index = 2; index < dataPointList.Count; index++)
        {
            var dataPoint = dataPointList[index];
            if (string.IsNullOrEmpty(dataPoint))
                continue;
            ChartDataObject cdo;
            if (DataPoints.datasets.Count <= index - 2)
            {
                cdo = new ChartDataObject();
                DataPoints.datasets.Add(cdo);
                cdo.label = ColumnObjects[index].propertyName;
            }
            else
                cdo = DataPoints.datasets[index - 2];

            cdo.data.Add(dataPoint);

            <—-THIS LINE THROWS THE ERROR —>
            DataPoints.datasets[index - 2] = cdo;
        }

        DataPointAPI DataPointResponse = new DataPointAPI()
        {
            data = DataPoints,
        };

        dataset.Add(DataPointResponse);
    }

    // Set some class field to contain these datapoints
    ChartData = dataset;
}

public class DataPointAPI
{
    public DataPoints data;
}

public class DataPoints
{
    public List<string> labels { get; set; }
    public List<ChartDataObject> datasets { get; set; }

    public DataPoints()
    {
        labels = new List<string>();
        datasets = new List<ChartDataObject>();
    }
}

public class ChartDataObject
{
    public string label { get; set; }
    public List<string> data { get; set; }

    public ChartDataObject()
    {
        data = new List<string>();
    }
}
Enigmativity
  • 113,464
  • 11
  • 89
  • 172
kjamp
  • 365
  • 3
  • 10
  • 37
  • By the way, give that you remove `[` and `]` and then split on `,` - is your OriginalData actually JSON? If so, there are better ways to parse it than that – Caius Jard Oct 27 '20 at 07:02

3 Answers3

2

Before whichever line of code causes the error, put something like:

if(someIndex >= someArray.Length)
  return new someType[someLengthYouWantTheNewArrrayToHave];

Change the names for whatever is relevant to your code (it isn't really easy to see which line of code throws this error you encounter). It's also not clear to me what you mean by "empty array" - usually it's either an array with length 0, bllut people sometimes mean an array where every element is null or zero. The essential logic is "if the index is at or greater than the array length, you're about to crash so do something else instead, like returning new string[2]". You'll also need to make sure that the return type of the method your code is in matches the type of the array you return.

I didn't recommend catching the exception because exceptions are expensive. If you can prevent raising them by detecting when you're about to access an array/collectionnusing an index that is greater than its length, then you should rather than trying code you know will crash and catching. Using exceptions for normal control flow is generally a no-no

Caius Jard
  • 72,509
  • 5
  • 49
  • 80
  • I just updated the code for clarity but it errors out in the index conditonal loop because the array ends at 4 so I'm stuck on that part – kjamp Oct 27 '20 at 06:54
  • A line in your question saying "this line of code throws the error: " would be most helpful.. – Caius Jard Oct 27 '20 at 07:01
  • Just updated it with that suggestion – kjamp Oct 27 '20 at 07:04
  • I disagree, sorry. You've put a comment in the code indicating that somewhere in the body of a large loop, the exception occurs. I wanted the exact single line – Caius Jard Oct 27 '20 at 07:04
  • Sorry I just updated – kjamp Oct 27 '20 at 07:07
  • And how many entries does `DataPoints.datasets` contain when the error throws? And what is the value of `index`? – Caius Jard Oct 27 '20 at 07:12
  • It contain 4 when the error is thrown but the value of index is how rows the array contains . I want it to return an empty array instead of throwing an error – kjamp Oct 27 '20 at 07:16
  • I really can't see why it would in the code as posted, [and I can't reproduce the problem](https://dotnetfiddle.net/Mcm5K8) . I believe I have, at least, told you how to do what you want but I'm not sure what you mean by "return an empty array" - you aren't using arrays and your method as it stands does not return anything, let alone an array. It seems illogical to suddenly start returning something when you don't already. Just do the check and stop the loop? – Caius Jard Oct 27 '20 at 08:02
1

Declare a function that does the job:

public DataPointAPI ProcessWspViewRow(WspViewRow) {
    DataPointAPI DataPointResponse = new DataPointAPI();
            
    var dataPointList = row.OriginalData.TrimStart('[').TrimEnd(']').Split(',').ToList();
    if (dataPointList.Count < 2) {
        // Assign here DataPointResponse.data = new DataPoints();
        return DataPointResponse;
    }
    DataPoints.labels.Add(dataPointList[1]);

            for (var index = 2; index< dataPointList.Count; index++)
            {
                var dataPoint = dataPointList[index];
                if (string.IsNullOrEmpty(dataPoint))
                    continue;
                ChartDataObject cdo;
                if (DataPoints.datasets.Count <= index - 2)
                {
                    cdo = new ChartDataObject();
                    DataPoints.datasets.Add(cdo);
                    cdo.label = ColumnObjects[index].propertyName;
                }
                else
                    cdo = DataPoints.datasets[index - 2];

                cdo.data.Add(dataPoint);
                DataPoints.datasets[index - 2] = cdo;
            }
            
               DataPointResponse.data = DataPoints;
    return DataPointResponse

}

Your code now becomes:

foreach (WspViewRow row in dataPointBuilder)
{
    dataset.Add(ProcessWspViewRow(row);
}
Athanasios Kataras
  • 25,191
  • 4
  • 32
  • 61
  • I may need to update my code because this didn't work for me, can you check after the update? – kjamp Oct 27 '20 at 06:52
-1

Try this:

try 
{
    // your code
}
catch (IndexOutOfRangeException)
{
    return Array.Empty<T>();
}

Where T is type of your array element.

Sergey Nazarov
  • 671
  • 3
  • 15