收集属性应该只读 – 漏洞?

在遵守代码分析错误的过程中,我正在更改我的属性以拥有私有的setter。 然后我开始尝试理解为什么多一点。 根据一些研究,MS说:

可写集合属性允许用户使用完全不同的集合替换集合。

答案在这里指出:

List对象上添加公共setter是危险的。

但它没有列出危险的原因 。 这就是我很好奇的部分。

如果我们有这个集合:

 public List Foos { get; set; } 

为什么要将setter设为私有? 显然我们不希望客户端代码替换集合, 但如果客户端可以删除每个元素,然后添加他们想要的东西,那么重点是什么? 这与完全替换系列不一样吗? 遵循此代码分析规则如何提供价值?

不公开setter可以防止为集合分配值为nullnull和没有任何值的集合之间存在差异。 考虑:

for (var value in this.myCollection){ // do something

当没有值时(即有人在每个值上调用Remove ),没有任何不好的事情发生。 但是,当this.myCollection为null时,将抛出NullReferenceException

代码分析假设您的代码在操作之前不检查myCollection是否为null。

它可能也是System.Collections.Concurrent定义的线程安全集合类型的附加安全措施。 想象一下,一些线程试图通过覆盖它来替换整个集合。 通过删除公共setter,线程唯一的选择是调用线程安全的AddRemove方法。

如果你暴露了一个IList(这将是更好的做法),消费者可以用一个完全不同的实现IList的类替换该集合,这可能具有不可预测的影响。 您可以订阅该集合上的事件,也可以订阅该集合中您现在错误响应的项目​​。

除了SimpleCoder的空检查(当然,这很重要)之外,您还需要考虑其他事项。

  • 有人可以替换List,导致线程安全性出现大问题
  • 替换列表的事件不会发送给旧订阅者的订阅者
  • 你需要暴露更多,更多的行为。 例如,我甚至不会公开吸气剂。

为了澄清第3点,不要做cust.Orders.clear() ,而是创建一个名为clearOrders()的函数。

如果客户不允许超过信用额度怎么办? 如果公开列表,则无法控制它。 您必须在每个可能添加订单的地方检查(以及所有其他业务逻辑)。 哎呀! 这有很多潜在的错误。 相反,您可以将它全部放在addOrder(Order o)函数中,并且正好像下雨一样。

对于几乎每一个(我会说每一个,但有时候作弊感觉很好……)商务舱,每个属性都应该是私有的,以便获取和设置,并且如果可行的话,也可以使它们只读。 通过这种方式,您class级的用户只能获得行为。 尽可能多地保护您的数据!

ReadOnlyCollection和ReadOnlyObservableCollection仅存在于只读集合scenearios中。

ReadOnlyObservableCollection对于WPF / Silverlight / Metro应用程序中的单向绑定非常有用。

如果您的Customer类具有List属性,则此属性应始终具有私有setter,否则可以通过以下方式从客户对象外部更改:

 customer.Orders = new List //this could overwrite data. 

始终使用集合的添加和删除方法。

应通过以下方式在Customer构造函数内创建订单列表:

 Orders = new List(); 

你真的想在你的代码中检查所有的customer.Orders != null订单customer.Orders != null然后对订单进行操作?

或者您按照建议在客户对象中创建Orders属性,并且永远不会检查customer.Orders == null而只是枚举Orders,如果其计数为零则没有任何反应…