4

在坚持代码分析错误的过程中,我正在将我的属性更改为具有私有设置器。然后我开始试图理解为什么更多。根据一些研究,MS

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

答案在这里指出:

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

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

如果我们有这个集合:

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

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

4

5 回答 5

9

不公开设置器可防止为集合分配值的情况nullnull和没有任何值的集合之间是有区别的。考虑:

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

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

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

它可能也是对System.Collections.Concurrent. 想象一下某个线程试图通过覆盖它来替换整个集合。通过摆脱公共设置器,线程唯一的选择是调用线程安全AddRemove方法。

于 2012-07-05T17:34:49.410 回答
2

如果您要公开 IList(这将是更好的做法),则消费者可以将集合替换为完全不同的实现 IList 的类,这可能会产生不可预知的影响。您可能已经订阅了该集合上的事件,或者您现在错误响应的该集合中的项目。

于 2012-07-05T17:47:27.673 回答
2

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

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

为了澄清第 3 点,不要这样做cust.Orders.clear(),而是调用一个函数clearOrders()

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

For almost every (I'd say every, but sometimes cheating feels good...) business class, every property should be private for get and set, and if feasible make them readonly too. In this way, users of your class get only behaviors. Protect as much of your data as you can!

于 2012-07-05T17:54:57.153 回答
1

ReadOnlyCollectionReadOnlyObservableCollection仅适用于只读集合场景。

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

于 2012-07-05T17:39:20.683 回答
0

如果你有一个带有 List 属性的 Customer 类,那么这个属性应该总是有一个私有设置器,否则它可以通过以下方式从客户对象外部更改:

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

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

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

Orders = new List<Order>();

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

或者您按照建议在您的客户对象中创建 Orders 属性,并且从不检查customer.Orders == null而是仅枚举 Orders,如果它的计数为零,则不会发生任何事情......

于 2012-07-05T17:45:34.503 回答