LINQ出错:Sequence不包含任何元素

时间:2015-03-12 07:41:44

标签: c# multithreading linq

有时,我的用户会遇到以下问题:在日志文件中我可以看到抛出此异常( 序列不包含任何元素

我在周围搜索,当您尝试在空列表中访问或使用聚合时,可以看到此异常。

我搜索了这个异常的代码(太糟糕了没有记录堆栈跟踪),以及唯一的"潜力"罪魁祸首是以下行(使用Fist(),Last(),Single()或任何Aggregate)。但是,我无法理解为什么,也不能在我的本地复制。请帮忙提醒。

if (data.Any())
    return data.OrderByDescending(d => d.UpdatedTime).First().UpdatedTime;

此处dataList<MyObject>MyObject具有DateTime属性UpdatedTime

=====更多周边代码=====

这是我在日志中得到未处理的异常的地方。 GetRecentUpdates方法有自己的try catch块,因此排除了。

public ActionResult GetUpdatedTime(long lastUpdated) {
    var data = dataAccess.GetRecentUpdates(lastUpdated);
    var html = htmlBuilder.Build(data);
    return Content(html);
}

public List<MyObject> GetRecentUpdates(long lastUpdatedInTicks) {
    var list = _cache.GetRecentRequests(_userCache.UserId);
    if (list != null) {
        var lastUpdated = new DateTime(lastUpdatedInTicks);
        list = list.Where(l => l!=null && l.UpdatedTime > lastUpdated).ToList();
    }
    return list ?? new List<MyObject>();
}

public List<MyObject> GetRecentRequests(string userId) {
     List<MyObject> requests = null;
     try {
         // simplied but the idea stays
         requests = dictionary.Get(userId);
         commonRequests = dictionary.Get("common");

         if (requests != null) {
             if (commonRequests != null)
                 requests = requests.Union(commonRequests).ToList();
         } else {
             request = commonRequests;
         }

         if (requests != null) {
             requests = requests.OrderByDescending(r => r.CreatedDateTime).ToList();
     }
     catch (Exception ex) {
         // log the exception (handled)
     }

     return requests;
}

public string Build(List<MyObject> data) {
    var lastUpdated = DateTime.MinValue;
    if (data.Any())
        lastUpdated = data.OrderByDescending(d => d.UpdatedTime).First().UpdatedTime;
    return String.Format("<tr style=\"display:none\"><td><div Id='MetaInfo' data-lastUpdated='{0}' /></td></tr>", lastUpdated.Ticks);
}

javascript每隔10秒调用GetUpdatedTime。通常一切都很顺利,但每隔一段时间,就会抛出这个异常。一旦它被抛出,它会每隔10秒抛出一次,直到用户刷新页面。

4 个答案:

答案 0 :(得分:1)

<强>更新

经过一些调查之后的另一个版本:正如您所说,您的代码在多线程环境中运行,并且data对象可以由两个或多个线程访问。由于它是reference类型变量,因此可以修改它的引用。所以,考虑这种情况:

第一个线程进入Build方法并检查条件:

if (data.Any())

此时data不为空,因此它会进入true块。 正好在这个时间另一个线程进入Build方法,但在那一刻,data变量为空,并且所有引用都指向空{{1} }。但是第一个线程已进入List块:

true

它失败了你的例外。现在好消息:你可以通过多种方式解决它:

  • 首先,检查创建lastUpdated = data.OrderByDescending(d => d.UpdatedTime).First().UpdatedTime; 逻辑。可能是,它是静态或共享变量,或者是从中填充的对象,是静态变量还是共享变量,并且您具有此资源的竞争条件。您可以更改其创建的逻辑或将其包装到某个同步原语中,这样唯一的一个线程可以同时data但这会影响程序的性能)。
  • 更改Build的逻辑 - 不能肯定地说,但我认为情况是这样的:GetRecentRequests一直是空的,并且对于第一个线程{{1得到了一些数据,但没有第二个线程的数据,并且commonRequests对象被覆盖并且为空。 调试方法:在测试运行期间向程序添加dictionary原语,等待10-15个线程等待屏障。之后,他们将同时开始构建您的数据并且错误将很有可能发生(不要插入断点 - 它们将使您的线程同步)。
  • 制作data对象的本地副本,如下所示:

    Barrier

希望这有帮助。


如果某些数据可用,您的代码正在检查,之后按日期过滤数据。当您使用LINQ扩展方法时,我认为datavar localData = data.Select(d => d).ToList(); 对象,而不是data,因此,当您调用IEnumerable方法时,它被枚举,之后,您正在调用List方法,枚举

因此,如果您的数据是某种Any()方法的结果,则会对其进行一次枚举,并且第二次没有数据,并且序列为空。

考虑更改您的代码以使用First()yeild return数据,或者如果没有数据,则使用List方法获得Array对象,像这样:

FirstOrDefault

null

答案 1 :(得分:0)

如果data集合的任何元素满足data.Any()的谓词,则代码会先检查。由于没有谓词,此调用等同于告诉您data集合是否包含元素。

出于这个原因,我认为不行

return data.OrderByDescending(d => d.UpdatedTime).First().UpdatedTime;

是真正的问题,因为在空集合中执行某些操作时会抛出消息Sequence contains no elements的异常。由于data中的元素(然后data.Any()返回true),因此例外是关于代码中的另一行。

您应该向应用程序添加更多日志记录,以便获得异常的完整堆栈跟踪并更好地了解导致错误的行。

答案 2 :(得分:0)

尝试使用FirstOrDefault()方法。

var lastUpdated = DateTime.MinValue;
var first = data.OrderByDescending(d => d.UpdatedTime).FirstOrDefault();
if (first != null)
{
  lastUpdated = first.UpdatedTime;
}

答案 3 :(得分:0)

我不知道MyObject定义是什么样的。但我在猜测 UpdatedTime字段为DateTime?。如果是这样,它会在最后一种方法发生时:

lastUpdated = data.OrderByDescending(d => d.UpdatedTime).First().UpdatedTime;
return String.Format("<tr style=\"display:none\"><td><div Id='MetaInfo' data-lastUpdated='{0}' /></td></tr>", lastUpdated.Ticks);

UpdatedTimenulllastUpdated.Ticks投放NullReferenceException