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

时间:2012-07-05 17:32:47

标签: c# oop code-analysis

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

  

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

答案here说明:

  

List<T>对象上添加公共设置器是危险的。

原因为什么它的危险并未列出。这就是我很好奇的部分。

如果我们有这个系列:

public List<Foo> Foos { get; set; }

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

5 个答案:

答案 0 :(得分:9)

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

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

如果没有值(即有人在每个值上调用Remove),则不会发生任何不良情况。但是,如果this.myCollection为空,则会抛出NullReferenceException

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

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

答案 1 :(得分:2)

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

答案 2 :(得分:2)

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

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

为澄清第3点,请勿执行cust.Orders.clear(),而应制作名为clearOrders()的函数。

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

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

答案 3 :(得分:1)

ReadOnlyCollectionReadOnlyObservableCollection仅适用于只读集合scenearios。

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

答案 4 :(得分:0)

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

customer.Orders = new List<Order> 
//this could overwrite data.

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

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

Orders = new List<Order>();

你真的想在代码中的任何地方检查customer.Orders != null然后对订单进行操作吗?

或者您按照建议在客户对象中创建Orders属性,从不检查customer.Orders == null而只是枚举订单,如果其数量为零则没有任何反应......