我有一个公共属性(AllCustomers),它是由私有财产的延迟加载支持。
据我所知,公共财产应该是IEnumerable的( “程序接口,而不是实现” )。
不过,我可以看到两种方式来构建私有财产。
第一个选择,与私人列表 -
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;
}
}
我觉得第一个选项出现更正确的,因为它会一度创出数据库和存储结果,而第二个将导致多个数据库命中。
我的问题是 -
- 我在我的分析是正确的?
- 什么是不同方法的含义是什么?
- 有没有第二个选择将是首选的任何时候?
- 有没有更好的,更地道的方式表达了第二个选项?
这里涉及到“懒惰”的几个层次。 一个是固有的懒惰IEnumerable
实现,另一种是懒惰实现你自己添加到您的财产。
你的第一个实现将访问数据库一次,第一次AllCustomers
访问。 它将构建查询GetAllCustomers
并执行它,当你调用ToList
,本地存储的结果。
你的第二个实施也将访问数据库只有一次(假设你的LINQ的实现是半路出家)。 然而,这将是晚于第一个场景-甚至称您AllCustomer
属性将只返回一个IQueryable
,当这只会进行AllCustomers
实际上访问或枚举。 这可能会立即之后,或不 - 这是一个懒惰的实现。 同样,假设你的LINQ提供程序是不是太傻了,遍历整个集合将仍然只打了DB一次。
你为什么要选择第一个选项呢? 因为(再次,取决于实现),遍历AllCustomers
两次会打的DB两次。 ReSharper的,够方便,警告我们,当我们有一个可能的多个枚举IEnumerable
。 在本地存放List
将确保我们保持一个缓存的本地副本。 为了确保这在代码中明确表示,考虑曝光的IReadOnlyList
代替的IEnumerable
。
双方将打DB只有一次作为_AllCustomers
支持字段只有NULL
当调用getter时首次。
随着个人喜好的问题,我通常喜欢IEnumerable
在我的界面和方法的声明,但是支持领域是具体的类,如List<stuff>
。 使事情变得像修改您的收藏除其他更容易。
据我所知,公共财产应该是IEnumerable的(“程序接口,而不是实现”)。
这种认识是错误的。 规划在接口原则不说你应该编程, 哪个接口。 在你的榜样。 我会暴露IList<T>
并使其只读假设你不希望消费者修改列表:
private List<Customer> _AllCustomers;
public IList<Customer> AllCustomers
{
get
{
if (_AllCustomers == null)
{
_AllCustomers = DAL.GetAllCustomers().ToList().AsReadOnly();
}
return _AllCustomers;
}
}