gpt4 book ai didi

c# - Linq running total 第一个值添加到自身

转载 作者:可可西里 更新时间:2023-11-01 09:10:04 27 4
gpt4 key购买 nike

我有下面的计算客户帐户状态的运行总计,但是他的第一个值总是添加到自身,我不确定为什么 - 虽然我怀疑我错过了一些明显的东西:

    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

我做错了什么?

编辑:根据下面的 ahruss 评论,我在我的 View 中调用 Any() 的结果,导致第一个被评估两次 - 为了解决我将 ToList() 附加到我的查询。

谢谢大家的建议

最佳答案

在调用末尾添加一个 ToList() 以避免重复调用选择器。

这是一个具有副作用的有状态 LINQ 查询,其本质上是不可预测的。在代码的其他地方,您调用了导致第一个元素被计算的东西,例如 First()Any()。通常,在 LINQ 查询中产生副作用是很危险的,当您发现自己需要它们时,是时候考虑是否应该只用 foreach 代替了。

编辑,或者为什么会这样?

这是 LINQ 查询计算方式的结果:在您实际使用查询结果之前,集合实际上没有任何变化。它不评估任何元素。相反,它存储 Abstract Expression Trees或者只是评估查询所需的委托(delegate)。然后,它仅在需要结果时才评估这些结果,除非您明确存储结果,否则它们会在之后被丢弃,并在下一次重新评估。

所以这就产生了一个问题,为什么每次都有不同的结果?答案是 runningTotal 只在第一次初始化。之后,它的值就是上次执行查询后的值,这可能会导致奇怪的结果。

这意味着问题很容易就是“为什么总数总是两倍于应有的数额?”如果提问者正在做这样的事情:

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 的原因,它绕过了它并强制立即执行。

关于c# - Linq running total 第一个值添加到自身,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25037055/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com