MIcheal David
MIcheal David

Reputation: 149

How to check if a List<T> Index is null

I have a method that calculates total amount for each month from the db, as shown.

 public static List<Sale> ChartMonthlySalePerYear()
    {
        using (SQLiteConnection con = new SQLiteConnection(Connection.DatabaseLocationString))
        {
            SQLiteCommand cmd = null;
            string query = String.Format("SELECT  strftime('%m', SaleDate)  AS  month,  SUM(AmountPaid)  AS  sum_amountpaid   FROM  {0}   WHERE   strftime('%Y', SaleDate)  =  @1  GROUP BY   strftime('%m', SaleDate)  ", Sale.TABLE_NAME);
            cmd = new SQLiteCommand(query, con);
            cmd.Parameters.Add(new SQLiteParameter("@1", Properties.Settings.Default.ChartYearlyDisplay));
            con.Open();
            SQLiteDataReader reader = cmd.ExecuteReader();

            var list = new List<Sale>();
            while (reader.Read())
            {
                Sale value = new Sale()
                {
                    Months = reader["month"].ToString(),
                    SUMAmountPaid = Convert.ToDecimal(reader["sum_amountpaid"])
                };
                list.Add(value);
            }
            con.Close();

            return list;

        }
    }

And it returns a List like these by months,

And this is where is use the method.

List<Sale> sum = SaleViewModel.ChartMonthlySalePerYear();
                Jan = sum[0].SUMAmountPaid;
                Feb = sum[1].SUMAmountPaid;
                Mar = sum[2].SUMAmountPaid;
                Apr = sum[3].SUMAmountPaid;
                May = sum[4].SUMAmountPaid;
                Jun = sum[5].SUMAmountPaid;
                Jul = sum[6].SUMAmountPaid;
                //For Ausgust
                if (sum[7] != null)
                    Aug = 0;
                else
                    Aug = sum[7].SUMAmountPaid;
                //For September
                if (sum[7] != null)
                    Sep = 0;
                else
                    Sep = sum[7].SUMAmountPaid;

My challenge now is, there is no value for Aug & Sep, i want to check first before i give it a default value, but its throwing an Exception. Index was out of range. Must be non-negative and less than the size of the collection. For Aug & Sep. Thanks in advance.

Upvotes: 0

Views: 1748

Answers (2)

Brett Caswell
Brett Caswell

Reputation: 1504

You should not be using an index approach to this, since your Sale type has a Months property that is being populated with the reader["month"] value. You can determine whether a month exists by using a predicate (Func<Sale, bool> delegate).

Using Linq, you can use the predicate with First or FirstOrDefault to return the first instance that evaluates to true.

List<Sale> sum = SaleViewModel.ChartMonthlySalePerYear();

Jan = sum.Where((item) => item.Months == 1).Select((item) => item.SUMAmountPaid).DefaultIfEmpty(0).First();
Feb = sum.Where((item) => item.Months == 2).Select((item) => item.SUMAmountPaid).DefaultIfEmpty(0).First();
Mar = sum.Where((item) => item.Months == 3).Select((item) => item.SUMAmountPaid).DefaultIfEmpty(0).First();
Mar = sum.Where((item) => item.Months == 4).Select((item) => item.SUMAmountPaid).DefaultIfEmpty(0).First();

or,

Jan = sum.Any((item) => item.Months == 1) ? sum.First((item) => item.Months == 1).SUMAmountPaid : 0;
Feb = sum.Any((item) => item.Months == 2) ? sum.First((item) => item.Months == 2).SUMAmountPaid : 0;
Mar = sum.Any((item) => item.Months == 3) ? sum.First((item) => item.Months == 3).SUMAmountPaid : 0;
Apr = sum.Any((item) => item.Months == 4) ? sum.First((item) => item.Months == 4).SUMAmountPaid : 0;

Alternatively

you could just .ForEach to iterate through your records and a switch case to map them.

List<Sale> sum = SaleViewModel.ChartMonthlySalePerYear()
    .ForEach((item) => {
        switch(item.Months)
        {
            case 1:
                Jan = item.SUMAmountPaid;
                break;
            case 2:
                Feb = item.SUMAmountPaid;
                break;
            case 3:
                Mar = item.SUMAmountPaid;
                break;
            case 4:
                Apr = item.SUMAmountPaid;
                break;
            case 5:
                May = item.SUMAmountPaid;
                break;
            case 6:
                Jun = item.SUMAmountPaid;
                break;
            case 7:
                Jul = item.SUMAmountPaid;
                break;
            case 8:
                Aug = item.SUMAmountPaid;
                break;
            case 9:
                Sept = item.SUMAmountPaid;
                break;
            case 10:
                Oct = item.SUMAmountPaid;
                break;
            case 11:
                Nov = item.SUMAmountPaid;
                break;
            case 12:
                Dec = item.SUMAmountPaid;
                break;
            default: //do nothing
                break;
        }
    });

Ensuring that Jan through Dec are 0 by default.

Upvotes: 0

Tim
Tim

Reputation: 6060

You want to check if the index is less than or equal to the list's length before accessing that index to avoid index out of range exceptions:

if (sum.Count <= 7) 
   Aug = 0;
else
   Aug = sum[7].SUMAmountPaid;

But this won't work like you are expecting if you have holes in your data. The index of the List isn't going to match the month if you do have holes in the data. If that is the case, consider using a Dictionary<int, Sale>():

var salesByMonth = new Dictionary<int, Sale>();
while (reader.Read())
{
    Sale value = new Sale()
    {
        Months = reader["month"].ToString(),
        SUMAmountPaid = Convert.ToDecimal(reader["sum_amountpaid"])
    };
    salesByMonth.Add(int.Parse(value.Months), value);
}

And

Sale value;
if (salesByMonth.TryGetValue(1, out value))
   Jan = value.SUMAmountPaid;
else
   Jan = 0;

if (salesByMonth.TryGetValue(2, out value))
   Feb = value.SUMAmountPaid;
else
   Feb = 0;

Upvotes: 6

Related Questions