【问题标题】:How to check if a List<T> Index is null如何检查 List<T> 索引是否为空
【发布时间】:2017-08-02 18:54:01
【问题描述】:

我有一种方法可以从数据库中计算每个月的总金额,如图所示。

 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;

        }
    }

它会按月返回一个这样的列表,

  • 01 20000.00(例如一月)
  • 02 13000.00(例如二月)
  • 03 10000.00(例如三月)
  • 04 10000.00(例如四月)
  • 05 10000.00(例如五月)
  • 06 20000.00(例如六月)
  • 07 15000.00(例如 7 月) 但是其他月份还没有销售。

这就是使用方法的地方。

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;

我现在的挑战是,8 月和 9 月没有价值,我想先检查一下,然后再给它一个默认值,但它会抛出异常。 Index was out of range. Must be non-negative and less than the size of the collection. 8 月和 9 月。 提前致谢。

【问题讨论】:

  • 问题是什么,你提出的 if 条件不起作用?
  • 是的............
  • 你不需要在那里调用Close。你的using 语句应该处理实例并关闭它。另外,您对这份清单的处理不当。您根本不应该在这里使用 index 或 ElementAt,因为您有一个应该用于此目的的 Months 属性。
  • 好的,非常感谢您提供的信息。 @BrettCaswell

标签: c# list indexing


【解决方案1】:

您想在访问该索引之前检查索引是否小于或等于列表的长度以避免索引超出范围异常:

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

但是,如果您的数据中有漏洞,这将不会像您期望的那样工作。如果您的数据确实存在漏洞,则列表的索引将与月份不匹配。如果是这种情况,请考虑使用Dictionary&lt;int, Sale&gt;()

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);
}

还有

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;

【讨论】:

  • 对不起,没有像 Lenght 这样的属性。我已经更新了我的问题。
  • 对不起,我指的是计数,而不是长度。
  • @EdPlunkett-- 如果sum.Count==7 然后sum[7] 将抛出无效的索引范围,因为它会定义元素0..6。需要Count &lt;= 7 以防止这种情况发生。
【解决方案2】:

您不应该对此使用索引方法,因为您的 Sale 类型具有使用 reader["month"] 值填充的 Months 属性。您可以使用谓词 (Func&lt;Sale, bool&gt; delegate) 来确定一个月是否存在。

使用 Linq,您可以使用带有 FirstFirstOrDefault 的谓词来返回计算结果为 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();

或者,

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;

或者

您可以只使用.ForEach 来遍历您的记录并使用 switch case 来映射它们。

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;
        }
    });

确保JanDec 默认为0

【讨论】:

  • 将集合映射到这样的实例通常并不漂亮。您可以在这里定义一个方法调用MapSaleToMonthInstance(Sale item) { ...switch case...},而不是使用匿名Action&lt;Sale&gt; 函数,然后简单地将方法传递给.ForEach()...即.ForEach(MapSaleToMonthInstance)
  • 另请注意,您不必为这些方法中的任何一种使用 Linq 的 IEnumerable&lt;T&gt; 扩展方法。它们只是更容易使用它们;您还可以使用 switch case 概念执行foreach(var item in sum) 循环。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-11-03
  • 2017-10-22
  • 1970-01-01
  • 1970-01-01
  • 2011-07-15
  • 1970-01-01
  • 2022-07-20
相关资源
最近更新 更多