C# 重构LINQ。。。将属性和子属性从列表中相乘
我仍然在接受LINQ,我正在尝试将下面的foreach循环重构为它的LINQ等价物。这是我试图转换的foreach循环C# 重构LINQ。。。将属性和子属性从列表中相乘,c#,linq,refactoring,foreach,C#,Linq,Refactoring,Foreach,我仍然在接受LINQ,我正在尝试将下面的foreach循环重构为它的LINQ等价物。这是我试图转换的foreach循环 var NetTotal = 0M; foreach (var cheque in ListOfCheques) { var exchangeRate = (from exc in cheque.ExchangeRates where exc.Type == EnumExchangeRate.ForCheque
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;
我正在努力解决的重要问题
var query = from cheque in ListOfCheques
let excRates = cheque.ExchangeRates ?? Enumerable.Empty()
let rate = excRates.Where(x => x.Type == Something).Select(x => x.Rate).FirstOrDefault() ?? 1
select cheque.NetAmount * rate;
var netTotal = query.Sum();
如果Rate可为null,则可以在let语句中通过使其可为null(例如,Select(x=>newint?(x.Rate))来适应它,或者删除?1并在Select中适应它。这将使:
var query = from cheque in ListOfCheques
let excRates = cheque.ExchangeRates ?? Enumerable.Empty()
let rate = excRates.Where(x => x.Type == Something).Select(x => x.Rate).FirstOrDefault()
select cheque.NetAmount * (rate != 0 ? rate : 1);
这个怎么样
var query =
from cheque in ListOfCheques
let rate =
cheque.ExchangeRates
.Where(exc => exc.Type == EnumExchangeRate.ForCheque)
.Select(exc => exc.Rate)
.DefaultIfEmpty(1.0M)
.First()
select rate * cheque.NetAmount;
var NetTotal = query.Sum();
你的问题中给出的LINQ查询示例包含了你没有解释的“额外”内容,因此我只包含了
foreach
循环中的内容。与任何重构一样,只需一块一块地进行处理。首先,不要使用foreach
像这样使用Sum()
return ListOfCheques.Sum(c =>
{
var exchangeRate = (from exc in c.ExchangeRates
where exc.Type == EnumExchangeRate.ForCheque
select exc).FirstOrDefault();
return c.NetAmount * (exchangeRate ?? new ExchangeRate(){ Rate = 1 }).Rate;
});
(如果ExchangeRate.Rate属性的默认值是1就好了)
我已将exchangeRate函数重写为简单格式。是否确实要FirstOrDefault
而不是SingleOrDefault
var exchangeRate = c.ExchangeRates.
FirstOrDefault(ex => ex.Type == EnumExchangeRate.ForCheque);
然后可以将其交换到第一个语句中,将最终结果保留在下面
如果你想的话,一行
return ListOfCheques.Sum(c => c.NetAmount *
(c.ExchangeRates.FirstOrDefault(ex => ex.Type == EnumExchangeRate.ForCheque)
?? new ExchangeRate() { Rate = 1 }).Rate);
编辑
关于新汇率的澄清
与其做!=null?(amount*rate):(rate)
我更喜欢将ExchangeRate
对象与rate=1的新对象合并。我认为这提供了一段更平滑、更清晰的代码。我强烈建议您将默认汇率设为1.0,然后您可以简单地与新ExchangeRate()合并
,无需设置Rate属性
要在新的ExchangeRate对象中设置速率的默认值,只需将初始值设定项放入构造函数中即可
class ExchangeRate
{
public ExchangeRate()
{
this.Rate = 1.0;
}
// other stuff
}
由于Rate
是一种值类型,?
运算符将不起作用。感谢Kirk。这是一个优秀且经过深思熟虑的解决方案。您的解释为我提供了一种重构foreach循环的新方法!感谢您的时间。