有时,我的用户会遇到以下问题:在日志文件中我可以看到抛出此异常( 序列不包含任何元素 )
我在周围搜索,当您尝试在空列表中访问或使用聚合时,可以看到此异常。
我搜索了这个异常的代码(太糟糕了没有记录堆栈跟踪),以及唯一的"潜力"罪魁祸首是以下行(使用Fist(),Last(),Single()或任何Aggregate)。但是,我无法理解为什么,也不能在我的本地复制。请帮忙提醒。
if (data.Any())
return data.OrderByDescending(d => d.UpdatedTime).First().UpdatedTime;
此处data
为List<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秒抛出一次,直到用户刷新页面。
答案 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扩展方法时,我认为data
是var 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);
UpdatedTime
为null
,lastUpdated.Ticks
投放NullReferenceException
。