Linq and parameters
本文关键字:parameters and Linq | 更新日期: 2023-09-27 18:21:04
我只是想知道在性能方面什么更高效。我喜欢读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();
第二个应该更高效,因为第一个为每个源元素创建两个实例,并且有两个select迭代器在运行。
但是,差异是否显著取决于您的用例。如果元素的数量很小,dto构造函数非常轻(应该是这样),并且您没有在一个循环中执行数百万次,那么您不应该看到显著的差异。
在我看来,由于转换似乎有点长,您应该将此转换转换为一个新方法,在select中使用该方法。这样,您可以更容易地维护转换。
MyDto GetDto( MyResult resultItem)
{
...
}
var dtos = results.Select(GetDto);
如果你查看每个版本的流程,你会发现两个版本都有共同的事情,加上彼此唯一的事情。
这里有一些你喜欢的格式的伪代码:
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的调用,以及所需的开销,加上中间对象的额外对象实例化。因此,第二种格式在内存和时间上都更高效,因为它执行的操作更少,开销更少,创建的对象更少。
但是
然而,你必须问的真正问题是,这种低效率对你的真实用例有多大影响?这对你来说是一个问题,还是专注于它只是过早优化的又一个例子?
我对这个问题做了一个快速模拟,10000条源记录被处理了100次(总共处理了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秒。
是的,通常高效地编码会更好。不,如果你所沉溺的低效率可以用纳秒来衡量,那可能并不重要。。。除非您试图处理数十亿条记录,并经常重复该过程。
第二种方法更好。忽略真实的影响,简单的数学计算表明,1op<2个操作(在您的情况下,操作是在堆上分配对象)。请注意,当查询针对IEnumerable<T>
和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();