Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/apache-flex/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 重构LINQ。。。将属性和子属性从列表中相乘_C#_Linq_Refactoring_Foreach - Fatal编程技术网

C# 重构LINQ。。。将属性和子属性从列表中相乘

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

我仍然在接受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;
我正在努力解决的重要问题

  • 支票类中的“汇率”列表可能不存在,即不需要汇率
  • 如果没有找到汇率,则默认为1。我怎样才能设定。。。我希望将其设置为DefaultIfEmpty(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() ?? 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循环的新方法!感谢您的时间。