2011-08-24 55 views
2

我仍然与LINQ达成协议,我正在尝试将以下foreach循环重构为它的LINQ等效项。这是我正在尝试转换的foreach循环;重构LINQ ...从列表中乘以属性和子属性

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; 

我正在努力的重要观点;

  1. 这有可能是检查类中的“ExchangeRates”列表中不存在的,即它不需要汇率。
  2. 如果没有找到汇率,它应该默认为1.我该如何设置...我希望将其设置为DefaultIfEmpty(1)。

任何帮助,非常感谢。

回答

1

像任何重构一样,只是一块一块地去掉。首先,而不是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); 

编辑

在澄清?新的ExchangeRate()

而不是做!= null ? (amount * rate) : (rate)我宁愿合并ExchangeRate对象与Rate = 1的新对象。我认为这提供了一个更平滑和更清洁的一段代码。我强烈建议您将默认Rate设置为1.0,然后您可以简单地与new ExchangeRate()合并,而无需设置Rate属性。

要为在新EXCHANGERATE对象Rate的默认值,只是把初始化构造

class ExchangeRate 
{ 
    public ExchangeRate() 
    { 
     this.Rate = 1.0; 
    }  
    // other stuff 
} 
+0

谢谢柯克。一个优秀的,很好的解决方案。您的解释给了我一种重新审视我的foreach循环的新方法!谢谢你的时间。 – Rowen

0

你需要这个吗?

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

如果房价nulllable,你可以驾轻就熟,在通过使它可以为空(例如选择(X =>新的int let语句?(x.Rate))或删除?1,熟练地在它您的选择,这将使:?

  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); 
+0

由于'Rate'是数值型的''??运营商不会在里面工作。 – Enigmativity

+0

更新了答案 – Polity

0

这个怎么样在你的问题给出

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查询例子有“额外”的东西,你没有解释所以我只包括从你的的东西循环。