重构 LINQ ...将列表中的属性和子属性相乘
我仍在接受 LINQ,并且尝试将以下 foreach 循环重构为它的 LINQ 等效项。这是我试图转换的 foreach 循环;
var NetTotal = 0M;
foreach (var cheque in ListOfCheques)
{
var exchangeRate = (from exc in cheque.ExchangeRates
where exc.Type == EnumExchangeRate.ForCheque
select exc).FirstOrDefault();
NetTotal = exchangeRate != null ? NetTotal + cheque.NetAmount * exchangeRate.Rate : NetTotal + cheque.NetAmount;
}
return NetTotal ;
以及我想出的 LINQ 代码;
var NetTotal = (from cheque in ListOfCheques
join exc in ListOfCheques.SelectMany(b => b.ExchangeRates) on cheque.ID equals exrate.Cheque.ID into chequeWithRate
where income.ExchangeRates.Select(x => x.Type).Equals(EnumExchangeRate.ForCheque)
from ur in chequeWithRate.DefaultIfEmpty()
select ur).Sum(x => x.Cheque.NetAmount * x.Rate);
return NetTotal;
我正在努力解决的重要问题;
- Check 类中的“ExchangeRates”列表可能不存在,即它不需要汇率。
- 如果没有找到汇率,它应该默认为 1。我该如何设置...我希望在 DefaultIfEmpty(1) 中设置它。
非常感谢任何帮助。
I am still coming to terms with LINQ and I am trying to refactor the following foreach loop into it's LINQ equivalent. Here's the foreach loop that I am trying to convert;
var NetTotal = 0M;
foreach (var cheque in ListOfCheques)
{
var exchangeRate = (from exc in cheque.ExchangeRates
where exc.Type == EnumExchangeRate.ForCheque
select exc).FirstOrDefault();
NetTotal = exchangeRate != null ? NetTotal + cheque.NetAmount * exchangeRate.Rate : NetTotal + cheque.NetAmount;
}
return NetTotal ;
and the LINQ code that I've come up with;
var NetTotal = (from cheque in ListOfCheques
join exc in ListOfCheques.SelectMany(b => b.ExchangeRates) on cheque.ID equals exrate.Cheque.ID into chequeWithRate
where income.ExchangeRates.Select(x => x.Type).Equals(EnumExchangeRate.ForCheque)
from ur in chequeWithRate.DefaultIfEmpty()
select ur).Sum(x => x.Cheque.NetAmount * x.Rate);
return NetTotal;
The important points that I am struggling with;
- It's possible that the "ExchangeRates" list within the Cheque class does not exist, i.e. it does not need an exchange rate.
- If there is no exchange rate found it should default to 1. How can I set that... I was hoping to set it within DefaultIfEmpty(1).
Any help is greatly appreciated.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
就像任何重构一样,只需一点一点地削减即可。首先,不要像这样使用
foreach
而是使用Sum()
。(如果 ExchangeRate.Rate 属性的默认值为 1,那就太好了)
我会将 ExchangeRate 函数重写为简单的格式。您确定要
FirstOrDefault
而不是SingleOrDefault
吗?然后可以将其交换到第一个语句中,将最终结果留在下面。
如果你愿意的话,就一个衬垫!
编辑
对 ?? 的澄清new ExchangeRate()
而不是执行
!= null ? (amount * rates) : (rate)
我更喜欢将ExchangeRate
对象与 Rate = 1 的新对象合并。我认为这提供了更流畅、更清晰的代码。我强烈建议您将默认汇率设置为 1.0,然后您可以简单地与new ExchangeRate()
合并,而无需设置 Rate 属性。要在新的 ExchangeRate 对象中设置
Rate
的默认值,只需将初始值设定项放入构造函数中Like any refactoring, just chip away piece by piece. Firstly, rather than
foreach
just use aSum()
like so.(it'd be nice if the default value for the ExchangeRate.Rate property was 1)
I'd rewrite the exchangeRate function to a simple format. Are you sure you want
FirstOrDefault
and notSingleOrDefault
?and then this can be swapped into the first statement, leaving the resulting final product below.
A one liner if you want it to be!
edit
Clarification on the ?? new ExchangeRate()
Rather than doing the
!= null ? (amount * rate) : (rate)
I prefer to coalesce theExchangeRate
object with a new such object with Rate = 1. I think this provides a smoother and cleaner piece of code. I'd strongly suggest you make the default Rate be 1.0, and then you can simply coalesce with anew ExchangeRate()
, without needing to set the Rate property.To set a default value for the
Rate
in a new ExchangeRate object, just put the initializer inside the constructor这个怎么样?
您的问题中给出的 LINQ 查询示例包含您没有解释的“额外”内容,因此我只包含
foreach
循环中的内容。How about this?
Your LINQ query example given in your question has "extra" stuff that you didn't explain so I've only included the stuff from your
foreach
loop.你需要这个吗?
如果 Rate 可为空,您可以通过使其可为空来在 let 语句中适应它(例如 Select(x => new int?(x.Rate)) 或删除 ?? 1 并在您的 select 中适应它。这将使:
Do you need this?
If Rate is nulllable, you can either adept that in the let statement by making it nullable (e.g. Select(x => new int?(x.Rate)) or remove ?? 1 and adept it in your select. which will make: