集合类型的属性
当属性具有某种集合类型(例如
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; } }
这是标准方式。但是,当有人向您的代码写入内容时,他可以使用私有字段而不是属性,并且当您重构 get 操作时,您可能会遇到一些错误。
private List<MyItemClass> _myList;
public IList<MyItemClass> MyList{ get{ return _myList??(_myList = new List<MyItemClass>()); } }
这是先前延迟加载方式的变体。
您希望返回什么作为集合的默认值?如果这是空集合,你如何实现它?
When the property have some collection type like
public IList<MyItemClass> MyList{ get; }
IMHO, it's better to return empty collection instead of null value.
There are many ways to implement such functionality.
public IList<MyItemClass> MyList{ get; private set; }
public MyClass(){
MyList = new List<MyItemClass>();
}
This way allow to decrease number of class fields, but you need to put code in each constructor.
private List<MyItemClass> _myList = new List<MyItemClass>();
public IList<MyItemClass> MyList{ get{ return _myList; } }
This is standard way. But when somebody write something to your code he can use private field instead of property and you can get some bugs when you refactor get action.
private List<MyItemClass> _myList;
public IList<MyItemClass> MyList{ get{ return _myList??(_myList = new List<MyItemClass>()); } }
And this is the variant of the previous way with lazy loading.
What are you prefer to return as default value for collection? If this is empty collection how do you implement it?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
来自 .NET 设计指南:
扩展这一原则并将其与最小惊喜原则相结合应该非常清楚地表明您应该始终返回空集合而不是 null。
当您可以提供合理、直观的默认值时,为什么要把检查 null 的负担交给调用者呢?
封装的全部要点是在单一位置完成工作。它可能会使特定类的实现变得更加复杂,但它使得使用其 API 变得更加简单。
在大多数情况下,我将集合实现为包含类型中的不变量:
请注意使用 readonly 关键字,它确保一旦设置,列表就永远不会被替换或清空(但仍然可以重置)。这将列表保护为类的不变量,这使我免于在代码的其余部分中编写空检查。
延迟加载也是一种有效的编码习惯,但我仅在明确需要时才使用它。
From the .NET Design Guidelines:
Extending this principle and combining it with the Principle of Least Surprise should make it abundantly clear that you should always return an empty collection instead of null.
Why put the burden of checking for null on your caller when you can provide a sensible, intuitive default value?
The whole point of encapsulation is to do the work in a single place. It may make that specific class implementation a bit more complex, but it makes using its API simpler.
In most cases I implement the collection as an invariant in the containing type:
Notice the use of the
readonly
keyword which ensures that once set, the list can never be replace or nulled out (but it can still be reset). This protects the list as an invariant of the class, which safes me from writing null checks in the rest of my code.Lazy loading is also a valid coding idiom, but I only use it when I explicitly need it.
返回 null 确实不理想。对于替代方案;这取决于用途。 IMO,这个版本(从主帖子复制)是最简单的,但可以完成我们需要的一切:
并且作为一个优点,它可以与
XmlSerializer
一起使用,就像任何具有私有集的东西一样
不会工作(一个错误;它看到了setter,但没有注意到它不能使用它)。在我看来,这种懒惰的方法通常是矫枉过正的,因为在大多数有趣的情况下,你无论如何都会填充列表。
Returning
null
is indeed not ideal. For alternatives; it depends on the use. IMO, this version (copied from the main post) is the simplest yet does everything we need:and as an advantage, it'll work with
XmlSerializer
, where-as anything with aprivate set
won't work (a bug; it sees the setter but doesn't notice it can't use it).The lazy approach is usually overkill IMO, as in most interesting cases you're going to populate the lists anyway.
我通常使用在构造函数中初始化列表的变体。这可能会使构造函数更加“臃肿”,但构造函数的职责是构造对象。恕我直言,设置良好的默认值完全属于其职责范围。另外,作为奖励,您不必担心私有字段,这使得代码看起来更干净。
当然,重构确实会变得有点困难,但并不显着。不要忘记您可以链接构造函数(无论如何大多数时候),因此即使您有多个构造函数,您也应该只需编写一次初始化代码。
不过,不要忘记记录默认值是一个空集合。将集合字段设置为只读是一种很好的做法,除非您有充分的理由稍后重置它。
I usually use the variant where you initialize the list in the constructor. This might make the constructor more "bloated", but the constructors responsibility is constructing the object. Setting up good default values is IMHO completely within its responsibilities. Also, as a bonus you don't have to worry about private fields which makes the code look cleaner.
Sure, refactoring does get a little harder, but not significantly. Don't forget that you can chain your constructors (most of the time anyway) so even if you have several constructors you should be able to only have to write the initializer code once.
Don't forget to document that the default value is an empty collection though. And setting the collection field to readonly is good practice unless you have a good reason to reset it later.
选项 2(标准方式)并通过确保单元测试检查在您期望时返回空列表来避免重构问题。
Option 2 (standard way) and avoid the refactoring issue by ensuring your unit tests check the empty list is returned when you expect.
我更喜欢第二种变体,因为它更明显并且可以减少构造函数的大小。
但通常使该字段只读:
I prefer second variant because it's more obvious and decrease constructor size.
But is usually make this fields readonly: