c# – Linq运行总共添加了第一个值
我有以下计算客户帐户状态的运行总计,但是他的第一个值总是被添加到自己,我不知道为什么 – 虽然我怀疑我错过了一些明显的事情:
decimal? runningTotal = 0; IEnumerable<StatementModel> statement = sage.Repository<FDSSLTransactionHistory>() .Queryable() .Where(x => x.CustomerAccountNumber == sageAccount) .OrderBy(x=>x.UniqueReferenceNumber) .AsEnumerable() .Select(x => new StatementModel() { SLAccountId = x.CustomerAccountNumber,TransactionReference = x.TransactionReference,SecondReference = x.SecondReference,Currency = x.CurrencyCode,Value = x.GoodsValueInAccountCurrency,TransactionDate = x.TransactionDate,TransactionType = x.TransactionType,TransactionDescription = x.TransactionTypeName,Status = x.Status,RunningTotal = (runningTotal += x.GoodsValueInAccountCurrency) }); 哪些输出: 29/02/2012 00:00:00 154.80 309.60 30/04/2012 00:00:00 242.40 552.00 30/04/2012 00:00:00 242.40 794.40 30/04/2012 00:00:00 117.60 912.00 第一行的309.60应该是简单的154.80 我做错了什么? 编辑: 感谢大家的建议 解决方法
在调用结束时添加ToList(),以避免重复调用选择器.
这是具有副作用的有状态LINQ查询,这本质上是不可预测的.在代码的其他地方,你调用了一些导致第一个元素被评估的东西,像First()或Any().一般来说,在LINQ查询中产生副作用是很危险的,当你发现自己需要它们的时候,是时候考虑它是否应该是一个foreach. 编辑或为什么会发生这种情况? 这是LINQ查询被评估的结果:直到你实际使用查询的结果,没有什么真正发生的集合.它不评估任何元素.相反,它存储Abstract Expression Trees或只需要评估查询所需的代理.然后,只有当需要结果时,才会评估这些结果,除非您明确存储结果,否则将被丢弃,并在下次重新评估. 所以这个问题为什么每次都有不同的结果?答案是,runTotal仅在第一次初始化.之后,它的值是上次执行查询后的值,这可能会导致奇怪的结果. 这意味着问题可能很容易就是“为什么总是总是两倍呢?”如果asker做这样的事情: Console.WriteLine(statement.Count()); // this enumerates all the elements! foreach (var item in statement) { Console.WriteLine(item.Total); } 因为获取序列中元素数量的唯一方法是实际评估它们. 同样,在这个问题上,实际发生的是某个地方有这样的代码: if (statement.Any()) // this actually involves getting the first result { // do something with the statement } // ... foreach (var item in statement) { Console.WriteLine(item.Total); } 这似乎是无害的,但是如果你知道LINQ和IEnumerable如何工作,你知道.Any()与.GetEnumerator()基本相同.MoveNext(),这使得它更明显地需要获得第一个元素. 所有这一切归结为LINQ是基于延迟执行的事实,这就是为什么解决方案是使用ToList,它规避并强制立即执行. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |