集合类型的属性

8
当属性具有某些集合类型时,例如:
public IList<MyItemClass> MyList{ get; }

在我看来,返回空集合而不是null值更好。
有许多实现此功能的方法。

public IList<MyItemClass> MyList{ get; private set; }
public MyClass(){
    MyList = new List<MyItemClass>();
}

这种方法可以减少类字段的数量,但您需要在每个构造函数中放置代码。

private List<MyItemClass> _myList = new List<MyItemClass>();
public IList<MyItemClass> MyList{ get{ return _myList; } }

这是标准的方式。但是当有人向您的代码中写入内容时,他可以使用私有字段而不是属性,当您重构获取操作时可能会出现一些错误。
private List<MyItemClass> _myList;
public IList<MyItemClass> MyList{ get{ return _myList??(_myList = new List<MyItemClass>()); } }

这是先前的一种带有延迟加载的变体。

你更喜欢将什么作为集合的默认值返回?如果是空集合,你会如何实现它?

5个回答

2

根据.NET设计指南

为所有属性提供合理的默认值,确保这些默认值不会导致安全漏洞或极其低效的设计。

扩展这个原则并结合最小惊奇原则,应该明确地表明,你应该始终返回空集合而不是null。

为什么要让调用者检查null,当你可以提供一个合理、直观的默认值呢?

封装的整个重点在于在一个单一的位置完成工作。它可能会使特定类的实现变得更加复杂,但使用其API更加简单。

在大多数情况下,我将集合作为包含类型中的不变量来实现:

public class MyClass
{
    private readonly List<Foo> foos;

    public class MyClass()
    {
        this.foos = new List<Foo>();
    }
}

注意使用readonly关键字,它确保列表一旦设置就永远不能被替换或置空(但可以重置)。这将列表作为类的不变量进行保护,使我免于在代码的其余部分编写null检查。
懒加载也是一种有效的编码习惯,但我只会在明确需要时使用它。

1

返回null确实不是理想的选择。对于替代方案,这取决于使用情况。在我看来,这个版本(从主帖中复制)是最简单的,但可以完成我们需要的所有操作:

private List<MyItemClass> _myList = new List<MyItemClass>();
public IList<MyItemClass> MyList { get { return _myList; } }

作为一个优势,它将与XmlSerializer一起工作,而任何带有private set的东西不会工作(这是一个错误;它看到了setter但没有注意到它不能使用它)。

懒惰的方法通常在我看来过度,因为在大多数有趣的情况下,您仍然需要填充列表。


1

我通常使用在构造函数中初始化列表的变量。这可能会使构造函数更加“臃肿”,但构造函数的职责是构建对象。设置良好的默认值完全在其职责范围内。此外,作为奖励,您不必担心私有字段,这使得代码看起来更清洁。

当然,重构确实会变得有点困难,但并不显著。不要忘记您可以链接您的构造函数(大多数情况下),因此即使您有多个构造函数,您也应该能够只编写一次初始化器代码。

不要忘记记录默认值为空集合。将集合字段设置为只读是一个好习惯,除非您有很好的理由稍后重置它。


0

第二种选择(标准方式)是通过确保您的单元测试检查在您期望返回空列表时是否返回空列表,从而避免重构问题。


0
我更喜欢第二种变体,因为它更明显并且可以减少构造函数的大小。 但通常会将这些字段设置为只读:
private readonly List<MyItemClass> _myList = new List<MyItemClass>();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接