【问题标题】:Why does LINQ query throw an exception when I attempt to get a count of a type当我尝试获取类型的计数时,为什么 LINQ 查询会引发异常
【发布时间】:2010-09-08 10:58:07
【问题描述】:
public readonly IEnumerable<string> PeriodToSelect = new string[] { "MONTH" };  

var dataCollection = from p in somedata    
from h in p.somemoredate    
where h.Year > (DateTime.Now.Year - 2)    
where PeriodToSelect.Contains(h.TimePeriod)  
select new  
{  
    p.Currency, 
    h.Year.Month, h.Value                                                    
}; 

谁能告诉我为什么在下面的代码行会抛出异常?

int count = dataCollection.Count();  

这是个例外:

System.NullReferenceException: Object reference not set to an instance of an object.
   at System.Linq.Enumerable.<SelectManyIterator>d__31`3.MoveNext()
   at System.Linq.Enumerable.<SelectManyIterator>d__31`3.MoveNext()
   at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at ...

【问题讨论】:

  • 确切的例外是什么?您只发布了一个堆栈跟踪...
  • 我已经添加了完整的例外。
  • 由于 LINQ 的延迟评估,并且查看堆栈跟踪,我猜您的错误出现在创建 dataCollection 的代码中。在进行计数之前尝试var x = dataCollection.ToList(); - 如果它引发相同的错误,那么问题不在您发布的代码中。 (我假设 dataCollection 是一个 IEnumerable)。
  • 异常的最可能原因是 p.somemoredate 对于某些 p 为空。检查“somedata”是否有 somemoredate == null 的任何项目。
  • 对不起,我的意思是 someData.ToList(),而 someData 是一个 IEnumerable。

标签: c# linq exception-handling linq-to-objects


【解决方案1】:

当 linq2objects 尝试执行您的谓词或预测时,这看起来像是一个正常的空引用异常。

如果“somedata”集合的某些元素为空,如果“h.Year”为空(那是什么类型?),或者如果“p.somemoredate”为空..

【讨论】:

  • 这是正确的答案......有趣的是,我很久以前就已经支持 Albin 对这个问题的评论了。
【解决方案2】:

延期执行再次罢工!

(首先,我的第一个猜测是,这是由于 p.somemoredate 在您的集合中某处为空所致。)

鉴于您的示例,我们无法真正知道,因为您已经简化了正在查询的位。从表面上看,我会说任何“somedata”或“somemoredate”都是您需要查看的东西。

为了弄清楚这一点,(当我真的很绝望时)我将查询分成几部分,并观察抛出异常的位置。请注意 .ToArray() 调用,这将基本上“停止”延迟执行暂时发生:

var sd = somedata.ToArray();
var x  = (from p in sd from h in p.somemoredate.ToArray()).ToArray();  //My guess is that you'll get your exception here.

这样分解,更容易看出哪里抛出了异常,到哪里寻找问题。

【讨论】:

  • +1:除非我们获得更多信息,否则这是最可能的原因。我的意思是在我对这个问题的评论中说someData而不是dataCollection:)。
【解决方案3】:

在 Count() 语句中引发异常,因为 LINQ 使用延迟执行,并且在调用 .Count().ToList() 等之前不会执行实际的 LINQ 查询。

【讨论】:

  • 谢谢。那么这是否意味着 Linq 查询本身发生了实际错误?
  • 不,这意味着您没有向 IEnuberable 询问计数,您只是忘记了 .ToList()
  • @Stefanvds:不,在生成的 IQueryable/IEnumerable 上调用 Count() 方法非常好,而无需先调用 .ToList()。
  • 不幸的是,我转换为列表时仍然抛出异常?
  • 问题是您的属性之一为NULL,因此当它尝试进行比较时会引发异常...比较是在Contains...上执行的...但是当您做.Count()你真的检索到linq查询的结果..
【解决方案4】:

我遇到了同样的问题。令人讨厌的是,MS 没有为聚合函数提供内置的 null 检测和处理。另一个问题是,当我在处理仪表板/报告时,我想确保获得空值/空查询结果的 0 或 0 美元返回结果。所有这些表最终都会有数据,但在早期你会得到很多空返回。在阅读了有关该主题的多个帖子后,我想出了这个:

检索您要返回的字段或稍后首先应用聚合函数。 测试是否返回空值。如果检测到 null,则返回 0。

如果您确实返回了实际数据,那么您可以安全地使用/应用 Count 或 Sum 聚合 Linq 函数。

public ActionResult YourTestMethod()
{
    var linqResults = (from e in db.YourTable
                       select e.FieldYouWantToCount);

    if (linqResults != null)
    {
        return Json(linqResults.ToList().Count(), JsonRequestBehavior.AllowGet);
    }
    else
    {
        return Json(0, JsonRequestBehavior.AllowGet);
    }
}

下面的例子

public ActionResult YourTestMethod()
{
    var linqResults = (from e in db.YourTable
                       select e.Total);

    if (linqResults != null)
    {
        return Json(linqResults.ToList().Sum(), JsonRequestBehavior.AllowGet);
    }
    else
    {
        return Json(0, JsonRequestBehavior.AllowGet);
    }
}

【讨论】:

  • 我不认为添加默认的 null 处理真的会起作用,因为在不同的情况下,您可能希望以不同的方式处理 null。有时您可能希望排除它们,有时您可能希望使用默认值对它们进行 NVL/IsNull。编译器无法知道您的业务逻辑需要是什么。
猜你喜欢
  • 2021-04-25
  • 2020-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-13
  • 2013-05-08
  • 1970-01-01
  • 2012-08-13
相关资源
最近更新 更多