属性获取器中的 LINQ - 性能不佳



请考虑以下代码片段:

    private List<object> MyList;
    public List<object> SubSetOfList
    {
        get { return MyList.Where(p => p.Property == SomeValue).ToList(); }
    }

这是访问我感兴趣的列表子集的一种非常方便的方法。但是,我想它在性能方面可能无法很好地扩展。

我考虑的另一种模式如下。不过我不关心这个,因为它在复杂性方面存在扩展问题,因为我感兴趣的子集数量增加。

    private List<object> _myList;
    public List<object> WholeList
    {
        get { return _myList; }
    }
    private List<object> _valueAList; 
    public List<object> ValueAList
    {
        get { return _valueAList; }
    }
    private List<object> _valueBList;
    public List<object> ValueBList
    {
        get { return _valueBList; }
    }
    public void AddItem(object obj)
    {
        _myList.Add(obj);
        if (obj.SomePropety == valueA)
            _valueAList.Add(obj);
        if (obj.SomePropety == valueB)
            _valueBList.Add(obj);
    }

是否有一种或多种普遍接受的模式来处理这种行为?

这完全取决于您的要求。如果您有某种存储需求,您的第二个解决方案确实会扩展得很差。如果您有性能要求,则始终创建列表也可能缩放不良。

一个可能的解决方案是使用您的第一个解决方案,但存储结果列表并仅在访问时才创建它,例如

private List<object> MyList;
private List<object> _subList;
public List<object> SubSetOfList
{
    get { return _subList ?? (_subList = MyList.Where(p => p.Property == SomeValue).ToList();) }
}

这是一种懒惰的评估,因为它只做一次。您当然需要自己处理一致性,因为更改 MyList 需要使存储的子列表无效。

另一种解决方案是返回一个延迟计算的IEnumerable<object>。但请记住,这种类型的每个用户都需要一遍又一遍地重新评估它。如果你的操作包含许多First()Last()等,那么这实际上会更快,因为以前没有人评估过整个列表,就像(@D Stanley 提到的那样)。

但请注意,人们倾向于评估IEnumerables有时不止一次,从而导致明确的性能损失。 例如调用 Any(),然后调用 IEnumerable 的其他调用。然后调用者应该正确使用 ToList 等来仅评估列表一次。

还有一个重复:没有分析就没有性能声明

如前所述,在根据合理的替代方案进行衡量之前,不要假设任何事情都是性能问题。 也就是说,一些可能提高性能的选项是:

  1. 将列表公开为 IEnumerable s 而不是 List 以利用延迟执行。 (例如,像First这样的操作会更快,因为您不需要水合整个列表)
  2. 缓存
  3. 筛选的列表(确保在添加新项或更改影响列表的属性时清除缓存)
  4. 使用字典改进按属性查找(在添加项目或更改属性时再次维护字典)
  5. 按照您的建议维护单独的列表。

您必须决定性能改进是否值得额外的维护。 就个人而言,我会从一个更简单的解决方案开始,只有在改进证明风险和工作合理的情况下才进行重构。

相关内容

  • 没有找到相关文章

最新更新