LINQ的运行总计1附加值本身 [英] Linq running total 1st value added to itself

查看:165
本文介绍了LINQ的运行总计1附加值本身的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有低于此计算运行总计为客户账户状态,不过他第一个值将始终加上本身,我不知道为什么 - 尽管我怀疑我已经错过了一些显而易见的:

I have the below which calculates the running total for a customer account status, however he first value is always added to itself and I'm not sure why - though I suspect I've missed something obvious:

    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)
        });



它输出:

Which outputs:

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的评论,我打电话任何()的结果在我看来,造成第一个被两次评估 - 解决我追加了ToList()来我的查询

As per ahruss's comment below, I was calling Any() on the result in my View, causing the first to be evaluated twice - to resolve I appended ToList() to my query.

感谢所有为您的建议

推荐答案

添加了ToList( )来调用,避免选择重复调用的结束。

Add a ToList() to the end of the call to avoid duplicate invocations of the selector.

这是一个有状态的LINQ查询有副作用的,这是本质上不可预测的。代码中的其他地方,你叫导致的第一个元素进行评估,如的东西首先()任何()。一般情况下,它是危险的在LINQ查询副作用,当你发现自己需要它们,是时候考虑一​​下是否应该只是一个的foreach 来代替。

This is a stateful LINQ query with side-effects, which is by nature unpredictable. Somewhere else in the code, you called something that caused the first element to be evaluated, like First() or Any(). In general, it is dangerous to have side-effects in LINQ queries, and when you find yourself needing them, it's time to think about whether or not it should just be a foreach instead.

这是LINQ查询如何评估结果:直到你真正的使用的的查询结果,真的没什么恰好集合。它不评价任何元素。相反,它存储抽象表达式树或只是代表它需要评估查询。然后,这些评估需要的结果,只有当,除非你明确地存储结果,他们扔掉之后,和重新评估的下一次。

This is a result of how LINQ queries are evaluated: until you actually use the results of a query, nothing really happens to the collection. It doesn't evaluate any of the elements. Instead, it stores Abstract Expression Trees or just the delegates it needs to evaluate the query. Then, it evaluates those only when the results are needed, and unless you explicitly store the results, they're thrown away afterwards, and re-evaluated the next time.

因此,这使得问题,为什么它有不同的结果,每一次?答案是, runningTotal在大约只有初始化第一次。在此之后,它的价值是不管它是什么的查询,这可能会导致奇怪的结果的最后执行后。

So this makes the question why does it have different results each time? The answer is that runningTotal is only initialized the first time around. After that, its value is whatever it was after the last execution of the query, which can lead to strange results.

这意味着这个问题可能只是很容易地已经为什么总总两次它应该是什么?如果提问者在做这样的事情:

This means the question could just have easily have been "Why is the total always twice what it should be?" if the asker were doing something like this:

Console.WriteLine(statement.Count()); // this enumerates all the elements!
foreach (var item in statement) { Console.WriteLine(item.Total); }

由于只有这样,才能得到的序列中的元素数目是实际评估所有这些

Because the only way to get the number of elements in the sequence is to actually evaluate all of them.

同样的,其实在这个问题上所发生的事情是,某个地方有这样的代码:

Similarly, what actually happened in this question was that somewhere there was code like this:

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是如何工作的,你知道,。任何()是基本相同 .GetEnumerator()调用MoveNext(),这使得它更加明显,它需要得到第一个元素。

It seems innocuous, but if you know how LINQ and IEnumerable work, you know that .Any() is basically the same as .GetEnumerator().MoveNext(), which makes it more obvious that it requires getting the first element.

这一切都归结为一个事实,即LINQ是基于延迟执行,这也就是为什么解决方案是使用了ToList ,规避了与部队立即执行。

It all boils down to the fact that LINQ is based on deferred execution, which is why the solution is to use ToList, which circumvents that and forces immediate execution.

这篇关于LINQ的运行总计1附加值本身的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆