物业获取者中的LINQ - 表现不佳?

时间:2014-04-02 13:01:34

标签: c# performance linq design-patterns

请考虑以下代码段:

    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);
    }

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

2 个答案:

答案 0 :(得分:1)

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

  1. 将列表公开为IEnumerable而不是List,以利用延迟执行。 (例如First之类的操作会更快,因为你不需要为整个列表添加水合物)
  2. 缓存已过滤的列表(如果添加了新项目或更改了影响列表的属性,请确保清除缓存)
  3. 使用词典改进按属性查找(再次维护添加项目或更改属性的词典)
  4. 按照您的建议维护单独的列表。
  5. 您必须确定性能改进是否值得额外维护。就个人而言,我会从一个更简单的解决方案开始,只有在改进证明风险和工作合理时才进行重构。

答案 1 :(得分:1)

完全取决于您的要求。如果你有某种存储要求,你的第二个解决方案确实会严重扩展。 如果您有性能要求而不是总是创建列表也可能会严重缩放。

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

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等来仅对列表进行一次评估。

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