在给出SO问题的答案时,我被告知我的解决方案将引入一个变量闭包,因此性能稍差.所以我的问题是:
这是个问题
List.Where(s => s.ValidDate.Date == DateTime.Today.Year).ToList();
Run Code Online (Sandbox Code Playgroud)
这是我的解决方案.我介绍了变量yr来存储年份.
int yr = DateTime.Now.Year;
List.Where(s => s.ValidDate.Year == yr).ToList();
Run Code Online (Sandbox Code Playgroud)
这是答案的评论
kni*_*ttl 14
首先,这两个解决方案在功能上并不相同(如果您修复了将日期与int(.Date == .Today.Year)进行比较):
第一个片段重新评估DateTime.Today.Year列表的每个值,当迭代期间当前年份发生变化时,可以给出不同的结果
第二个代码段存储当前年份并重新使用该年份,因此结果列表中的所有项目都将具有相同的年份.(我个人采取这种方法,因为我想确保结果是理智的).
引入闭包是因为lambda从其外部作用域访问变量,它关闭了值yr.C#编译将生成一个新类,其中包含一个字段yr.所有引用yr都将替换为新字段,原始文件yr甚至不会存在于已编译的代码中
我怀疑通过引入一个闭包会有性能损失.如果有的话,使用闭包的代码会更快,因为它不必DateTime为每个列表项创建新实例,然后取消引用两个属性.它只需要访问编译器生成的闭包类的字段,该闭包类保存当前年份的int值.(任何想要比较生成的IL代码或配置两个片段的人?:))
除了knittl的答案,我想尝试和测量有和没有闭合的性能,这是我的测试看起来像:
internal class SomeData {
public DateTime ValidDate { get; set; }
// other data ...
}
class Program {
static void Main(string[] args) {
var stopWatch = new Stopwatch();
// Test with closure
IEnumerable<SomeData> data1 = CreateTestData(100000);
stopWatch.Start();
int yr = DateTime.Now.Year;
List<SomeData> results1 = data1.Where(x => x.ValidDate.Year == yr).ToList();
stopWatch.Stop();
Console.WriteLine("With a closure - {0} ms", stopWatch.Elapsed.Milliseconds);
// ### Output on my machine (consistently): With a closure - 16 ms
stopWatch.Reset();
// Test without a closure
IEnumerable<SomeData> data2 = CreateTestData(100000);
stopWatch.Start();
List<SomeData> results2 = data2.Where(x => x.ValidDate.Year == DateTime.Today.Year).ToList();
stopWatch.Stop();
Console.WriteLine("Without a closure - {0} ms", stopWatch.Elapsed.Milliseconds);
// ### Output on my machine: Without a closure - 33 ms
}
private static IEnumerable<SomeData> CreateTestData(int numberOfItems) {
var dt = DateTime.Today;
for (int i = 0; i < numberOfItems; i++) {
yield return new SomeData {ValidDate = dt};
}
}
}
Run Code Online (Sandbox Code Playgroud)
我测试的底线 - 正如我所预期的那样,带闭合的版本要快得多.