5

我需要优化广泛使用 linq 的大型应用程序。许多 linq 语句在 linq 扩展方法中创建匿名对象。一个例子 :-

// custom sort order
var sortedData = data.OrderBy(x => (new List<string>() {"Orange", "Apple", "Pear" }).IndexOf(x.Name));
foreach (var d in sortedData) {
    ....

问题是每次迭代都会创建一个新列表。

是否可以设置一个编译器标志来让编译器进行一些静态分析并将循环不变代码提取到循环之外?

4

5 回答 5

1

为什么不能自己拔出来?

var fruits = new [] {"Orange", "Apple", "Pear" };
var sortedData = data.OrderBy(x => fruits.IndexOf(x.Name));
foreach (var d in sortedData) {

此外,如果这些循环都在同一个类中,则使之成为该类fruitsstatic readonly成员。

于 2012-12-13T14:25:27.257 回答
1

我想很多人都被你的例子所吸引而错过了你真正的问题。

不,Visual Studio 中没有内置的简单工具可以静态地执行此操作(无需运行程序)。如果您可以运行程序并执行有问题的代码,有两个工具可以帮助您(您确实有具有 100% 代码覆盖率的单元测试,不是吗;))。一种是Visual Studio 中内置的分析器,另一种是CLR 分析器

我从未使用过 CLR 分析器,它可能只是 Visual Studio 中的旧版本。Visual Studio Profiler 可以向您显示是否正在创建大量对象(在您的示例中为列表),并查看在代码中创建这些对象的位置。它还可以向您显示哪些代码行执行时间最长,以便您知道将精力集中在哪里来加快程序速度。

如果您在运行分析器时遇到特定问题,我建议您针对该问题提出一个新问题,

于 2012-12-13T15:07:04.133 回答
0

您可以将 LINQ 更改为:

// Note the call to ToArray()
var sortedData = data.OrderBy(...).ToArray();

在这种情况下,该语句应该执行一次,并且循环的源是不变的。

于 2012-12-13T14:20:48.400 回答
0

您无法设置任何内容来自动为您解决此问题;您必须手动取出匿名对象:

var orderingList = new List<string>() { "Orange", "Apple", "Pear" };
var sortedData = data.OrderBy(x => orderingList.IndexOf(x.Name));
foreach (var d in sortedData) {
    ...
}

请注意,这不是订购列表的最有效方式,因为您必须遍历列表中的每个项目data;你最好用字典:

var ordering = new Dictionary<string, int> {
    {"Orange", 0}, {"Apple", 1}, {"Pear", 2} };
var sortedData = data.OrderBy(x => ordering.ContainsKey(x) ? ordering[x] : -1);
于 2012-12-13T14:25:37.263 回答
-1

检查 FxCop 的规则,也许你可以做些什么。

于 2012-12-13T14:30:52.933 回答