【问题标题】:Optimizing LINQ query invoving Where Newbie C# / LINQ question优化涉及 Where Newbie C# / LINQ 问题的 LINQ 查询
【发布时间】:2019-11-02 01:17:49
【问题描述】:

在以下简单、人为的示例中,我在 Where 子句中使用了一个方法 (GetAutomaticCars)。这导致 GetAutomaticCars 被调用四次。我知道解决这个问题的一种方法。只需先调用 GetAutomaticCars 并在查询中使用结果。我已经在下面的注释行中展示了它。我的问题是: 这是处理这个问题的唯一方法吗?编译器无法优化调用并意识到它只需要调用一次 GetAutomaticCars 对我来说似乎有点奇怪。我想答案可能是:“_cars 集合可能会改变(在另一个线程上)”。如果是这样,有没有办法在 C# 中表明情况并非如此?还是我必须按照我的建议先调用 GetAutomaticCars?

class Program
{
    static void Main(string[] args)
    {
        CarTest test = new CarTest();
        test.PerformTest();
    }
}


public class CarTest
{
    List<Car> _cars = new List<Car>() { new Car(1, "Mustang", false), new Car(2, "Corvette", false), new Car(3, "Subaru", true), new Car(4, "Volvo", true) };
    public void PerformTest()
    {

        // this will just call GetAutomaticCars once
        //var automaticCars = GetAutomaticCars();
        //var optimalCars = _cars.Where(i => automaticCars.Select(p => p.Id).Contains(i.Id)).ToList();

        // this will call GetAutomaticCars 4 times
        var optimalCars = _cars.Where(i => !GetAutomaticCars().Select(p => p.Id).Contains(i.Id)).ToList(); 
        Console.WriteLine("Optimal Cars");
        foreach (var car in optimalCars)
        {
            Console.WriteLine(car);
        }
    }

    private IEnumerable<Car> GetAutomaticCars()
    {
        return _cars.Where(p => p.Automatic == true);
    }
}
public class Car
{
    public Car(int id, string name, bool automatic)
    {
        Id = id;
        Name = name;
        Automatic = automatic;
    }

    public int Id { get; set; }
    public string Name { get; set; }
    public bool Automatic { get; set; }
}

【问题讨论】:

  • Where 查询实际上是一个循环。如果您有一个循环,则不会在循环内调用该方法,而是在进入循环之前调用它一次。所以是的,你应该在这里做同样的事情。
  • 您在 _cars 上的 Where on cars 中执行 Where...您确定要执行此操作而不是仅在 Where 上执行一次吗?你需要 ToList 吗?
  • 在这种情况下,您可以在 _cars 和 GetAutomaticCars 之间使用JoinGetAutomaticCars 将被调用一次。像 --- _cars.Join(GetAutomaticCars()............)
  • 谢谢-user1672994,我会玩的。 Olivier,我从专有代码中简化了。有一个 ToList 所以我离开了它。在更长的实际代码中,Wheres 更有意义。
  • 这就够了:var optimalCars = _cars.Where(car =&gt; car.Automatic != true);

标签: c# linq optimization


【解决方案1】:

我们可以在这里谈论很多。例如:

  • 编译器无法安全优化方法调用的各种原因。
  • 您可以利用 IQueryables 提出一种不必要的复杂方法来优化您正在谈论的呼叫。

但我认为最重要的一点是,您已经获得了想要抽象到另一种方法中的逻辑 (p =&gt; p.Automatic == true),并且您想要一种更简单、更有效的方法来应用此逻辑LINQ 查询比您迄今为止想出的要多。以下是我的建议:

    var optimalCars = _cars.Except(GetAutomaticCars()); 

您还可以从过滤现有汽车的概念中抽象出确定汽车是否自动的逻辑,然后更直接地使用该逻辑:

private IsCarAutomatic(Car c) => c.IsAutomatic;
private IsCarOptimal(Car c) => !IsCarAutomatic(c);

...
var optimalCars = _cars.Where(IsCarOptimal);

【讨论】:

  • 感谢 StriplingWarrior!你的第一个例子 (_cars.Except(GetAutomaticCars()) 很棒。GetAutomaticCars 只被调用一次,而不是我原来的“Where”子句。我想说我从未听说过“Except”命令,但在事实上我只是没想到在这种情况下使用它。整个练习对我来说强化了编写效率不高的代码很容易。1 和 4 之间没有什么区别,但我的实际代码有数千个“汽车”。谢谢!
猜你喜欢
  • 1970-01-01
  • 2022-12-13
  • 2019-04-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多