在私有的,延迟加载的属性中列出vs IEnumerable

时间:2014-01-14 06:54:24

标签: c# asp.net list ienumerable private-members

我有一个公共属性(AllCustomers),它由一个私有属性支持延迟加载。

我知道公共财产应该是IEnumerable("program to interfaces, not implementations")。

但是,我可以看到两种构建私有财产的方法。

第一个选项,私人列表 -

private List<Customer> _AllCustomers;
public IEnumerable<Customer> AllCustomers
{
    get
    {
        if (_AllCustomers == null)
        {
            _AllCustomers = DAL.GetAllCustomers().ToList(); 
        }
        return _AllCustomers;
    }
}

第二个选项,私有IEnumerable -

private IEnumerable<Customer> _AllCustomers;
public IEnumerable<Customer> AllCustomers
{
    get
    {
        if (_AllCustomers == null)
        {
            _AllCustomers = DAL.GetAllCustomers(); 
        }
        return _AllCustomers;
    }
}

我认为第一个选项看起来更正确,因为它会在数据库中命中一次并存储结果,而第二个选项会导致多个数据库命中。

我的问题是 -

  • 我的分析是否正确?
  • 不同方法的含义是什么?
  • 是否有时间选择第二种选择?
  • 是否有更好,更惯用的表达方式 第二个选择?

3 个答案:

答案 0 :(得分:1)

当第一次调用getter时,_AllCustomers支持字段仅为NULL时,两者都只会触发一次数据库。

作为个人偏好的问题,我通常在我的界面和方法声明中更喜欢IEnumerable,但是支持字段是具体类,例如List<stuff>。这样可以更轻松地修改您的馆藏。

答案 1 :(得分:1)

这里涉及几个级别的“懒惰”。一个是IEnumerable实现的固有懒惰,另一个是你自己添加到你的财产的懒惰实现。

第一次实现将在第一次访问AllCustomers时访问数据库。它将在GetAllCustomers中构建查询,并在您调用ToList时执行该查询,并在本地存储结果。

你的第二个实现只对数据库命中一次(假设你的LINQ实现已经过了一半)。但是,这将以后而不是第一个场景 - 即使调用AllCustomer属性也只会返回IQueryable,只有在AllCustomers时才会执行实际访问或枚举。这可能是紧接着,或者不是 - 这是一个更懒惰的实现。再说一次,假设您的LINQ提供程序不是太愚蠢,迭代整个集合仍然只会打到DB一次。

为什么要选择第一个选项?因为(再次,取决于实现),迭代AllCustomers 两次可能会两次击中数据库。当我们有一个IEnumerable的多次枚举时,Resharper足够方便地警告我们。将其存储在本地List中将确保我们保留缓存的本地副本。要确保在代码中明确表达,请考虑公开IReadOnlyList而不是IEnumerable

答案 2 :(得分:0)

  

我知道公共属性应该是IEnumerable(“程序到接口,而不是实现”)。

这种理解是有缺陷的。对接口进行编程的原则并不是说应该编程哪个接口。在你的例子中。我会公开IList<T>,并将其设为只读,假设您不希望消费者修改列表:

private List<Customer> _AllCustomers;
public IList<Customer> AllCustomers
{
    get
    {
        if (_AllCustomers == null)
        {
            _AllCustomers = DAL.GetAllCustomers().ToList().AsReadOnly(); 
        }
        return _AllCustomers;
    }
}