Linq和参数

时间:2015-11-09 04:52:24

标签: c# linq

我只是想知道什么是更有效的性能明智。我喜欢阅读values,而我的同事喜欢阅读value2

var values = results.Select(x => new CategoryMixWidgetValueDto
{
    Dimension = x.Dimension, 
    LpeAmount = x.LpeAmount == null ? 0 : double.Parse(x.LpeAmount, CultureInfo.InvariantCulture),
    BudgetAmount = x.BudgetAmount == null ? 0 : double.Parse(x.BudgetAmount, CultureInfo.InvariantCulture),
    Variance = x.Variance == null ? 0 : double.Parse(x.Variance, CultureInfo.InvariantCulture)
})
.Select(x => new CategoryMixWidgetValueDto
{
    Dimension = x.Dimension,
    LpeAmount = x.LpeAmount,
    BudgetAmount = x.BudgetAmount,
    Variance = (x.LpeAmount.DoubleEquals(0) && x.BudgetAmount.DoubleEquals(0)) ? 0 : x.BudgetAmount.DoubleEquals(0) ? null : (x.Variance),
}).ToList();


var values2 = results.Select(x =>
{
    var lpeAmount = x.LpeAmount == null ? 0 : double.Parse(x.LpeAmount, CultureInfo.InvariantCulture);
    var budgetAmount = x.BudgetAmount == null ? 0 : double.Parse(x.BudgetAmount, CultureInfo.InvariantCulture);
    var variance = x.Variance == null ? null : (double?)double.Parse(x.Variance, CultureInfo.InvariantCulture);
    return new CategoryMixWidgetValueDto
    {
        Dimension = x.Dimension,
        LpeAmount = lpeAmount,
        BudgetAmount = budgetAmount,
        Variance = (lpeAmount.DoubleEquals(0) && budgetAmount.DoubleEquals(0)) ? 0 : budgetAmount.DoubleEquals(0) ? null : variance
    };
}).ToList();

3 个答案:

答案 0 :(得分:1)

第二个应该更高效,因为第一个为每个源元素创建两个实例,并且你有两个选择迭代器正在进行。

但是,差异是否显着取决于您的使用案例。如果元素的数量很少,那么dto构造函数非常轻(应该是这样),并且你在循环中没有这么做数百万次,那么你就不应该看到显着的差异。

在我看来,由于转换似乎有些冗长,您应该将此转换转换为新方法,在select中使用。这样,您可以更轻松地维护转换。

MyDto GetDto( MyResult resultItem)
{
    ...
}

var dtos = results.Select(GetDto);

答案 1 :(得分:0)

如果您查看每个版本的流程,您会发现这两个版本都有常见的东西,以及一个或另一个独有的东西。

这是您首选格式的伪代码:

For each item in source:
    Call Select to perform:
        Convert input data types
        Create intermediate object from converted data
    Call Select on intermediate object to perform:
        Do calculations
        Create result object from calculation results
Gather results to new List object

第二个:

For each item in source:
    Call Select to perform:
        Convert input data types
        Do calculations
        Create result object from calculation results
Gather results to new List object

因此,您的格式还需要额外调用Select以及所需的开销,以及中间对象的其他对象实例化。因此,第二种格式在内存和时间方面都更有效 - 因为它执行的操作更少,产生的开销更少,并且创建的对象更少。

<强>然而...

您必须要问的真正问题是,这种低效率对您的实际用例有多大影响?这对您来说是一个问题,还是只关注它是另一个过早优化的例子?

我快速模拟了这个问题,处理了100次源记录10000次(总共处理了1000000个对象),计算输出而不是将它们放入List。以下是一些统计数据:

Time per item (method A): 3.1616 μs
Time per item (method B): 2.9895 μs
Difference: 172.09 ns
Overhead: ~5.8%

这看起来非常诅咒,但实际上可能并没有影响你的输出。对于每5.8百万百万输入记录,开销最终会浪费1秒。

是的,通常更有效地编码。不,如果您沉迷的低效率可以用纳秒来衡量,那可能并不重要......除非你试图处理数十亿条记录,并经常重复这个过程。

答案 2 :(得分:-1)

第二种方法更好。忽略真实的影响,简单的数学表明1 op&lt; 2 ops(在你的情况下op是在堆上分配对象)。请注意,当查询针对IEnumerable<T> vs IQueryable<T>时,存在很大差异 - 在后一种情况下,查询提供程序可以优化执行,因为所有内容都表达为表达式树,而在前者中,所有内容都执行你写它的方式。换句话说,IQueryable提供程序可以使两个变体以完全相同的方式执行。但事实并非如此。

甚至还有一种特殊的LINQ语法支持第二种情况,如果构造完全等效,则不需要它:

var values2 = (from x in results
    let lpeAmount = x.LpeAmount == null ? 0 : double.Parse(x.LpeAmount, CultureInfo.InvariantCulture)
    let budgetAmount = x.BudgetAmount == null ? 0 : double.Parse(x.BudgetAmount, CultureInfo.InvariantCulture)
    let variance = x.Variance == null ? null : (double?)double.Parse(x.Variance, CultureInfo.InvariantCulture);
    select new CategoryMixWidgetValueDto
    {
        Dimension = x.Dimension,
        LpeAmount = lpeAmount,
        BudgetAmount = budgetAmount,
        Variance = (lpeAmount.DoubleEquals(0) && budgetAmount.DoubleEquals(0)) ? 0 : budgetAmount.DoubleEquals(0) ? null : variance
    }
).ToList();