用linq清理一个简单的foreach

时间:2009-05-19 19:12:37

标签: c# linq

以下方法非常简单,我试图通过将行项的另一个属性与父对象的查找匹配来确定行项目费率。有一些我不喜欢它的东西,我正在寻找优雅的解决方案,以使方法更小,更有效,或两者兼而有之。它适用于它的当前状态,并不像它显然效率低或任何东西。这不是关键任务或任何事情,更多是好奇心。

    private decimal CalculateLaborTotal()
    {
        decimal result = 0;

        foreach (ExtraWorkOrderLaborItem laborItem in Labor)
        {
            var rates = (from x in Project.ContractRates where x.ProjectRole.Name == laborItem.ProjectRole.Name select x).ToList();
            if (rates != null && rates.Count() > 0)
            {
                result += laborItem.Hours * rates[0].Rate;
            }
        }
        return result;
    }

我喜欢使用List<T>.ForEach()的想法,但我在保持简洁到易于阅读/维护方面遇到了一些麻烦。有什么想法吗?

3 个答案:

答案 0 :(得分:4)

这样的事情应该这样做(未经测试!):

var result = 
    (from laborItem in Labor
     let rate = (from x in Project.ContractRates 
                 where x.ProjectRole.Name == laborItem.ProjectRole.Name 
                 select x).FirstOrDefault()
     where rate != null
     select laborItem.Hours * rate.Rate).Sum();

或者(假设只有一个比率可以匹配)联接甚至更整洁:

var result = 
    (from laborItem in Labor
     join rate in Project.ContractRates
         on laborItem.ProjectRole.Name equals rate.ProjectRole.Name
     select laborItem.Hours * rate.Rate).Sum();

答案 1 :(得分:2)

好的,这个怎么样:

// Lookup from name to IEnumerable<decimal>, assuming Rate is a decimal
var ratesLookup = Project.ContractRates.ToLookup(x => x.ProjectRole.Name,
                                                 x => x.Rate);

var query = (from laborItem in Labor
             let rate = ratesGroup[laborItem].FirstOrDefault()
             select laborItem.Hours * rate).Sum();

这里的优点是您不需要每次都查看可能很大的合同费率列表 - 您只需构建一次查询。当然,这可能不是问题。

答案 2 :(得分:0)

省略rates != null检查 - linq查询可能为空,但不是null。 如果您只需要列表的第一个元素,请使用List.FirstList.FirstOrDefault

使用List<T>.ForEach没有优势。