如何公开集合属性? [英] How to expose a collection property?

查看:24
本文介绍了如何公开集合属性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

每次我创建一个具有集合属性的对象时,我都会来回寻找最好的方法吗?

Every time I create an object that has a collection property I go back and forth on the best way to do it?

  1. 带有 getter 的公共属性返回对私有变量的引用
  2. 显式 get_ObjList 和 set_ObjList返回和创建新的或克隆的方法每次都有对象
  3. 显式 get_ObjList 返回一个IEnumerator 和一个 set_ObjList接受 IEnumerator

如果集合是一个数组(即 objList.Clone())与一个列表,这有什么不同吗?

Does it make a difference if the collection is an array (i.e., objList.Clone()) versus a List?

如果将实际集合作为引用返回是如此糟糕,因为它会创建依赖关系,那么为什么要返回任何属性作为引用呢?任何时候您将子对象作为引用公开时,除非子对象具有属性更改事件,否则可以在父对象不知道"的情况下更改该子对象的内部结构.是否存在内存泄漏风险?

If returning the actual collection as a reference is so bad because it creates dependencies, then why return any property as a reference? Anytime you expose an child object as a reference the internals of that child can be changed without the parent "knowing" unless the child has a property changed event. Is there a risk for memory leaks?

而且,选项 2 和 3 不会破坏序列化吗?这是一个问题 22 还是您必须在拥有集合属性的任何时候实现自定义序列化?

And, don't options 2 and 3 break serialization? Is this a catch 22 or do you have to implement custom serialization anytime you have a collection property?

通用 ReadOnlyCollection 似乎是一般用途的一个很好的折衷方案.它包装一个 IList 并限制对它的访问.也许这有助于内存泄漏和序列化.但是它仍然有枚举问题

The generic ReadOnlyCollection seems like a nice compromise for general use. It wraps an IList and restricts access to it. Maybe this helps with memory leaks and serialization. However it still has enumeration concerns

也许这取决于.如果您不关心该集合是否被修改,则只需将其公开为每个 #1 的私有变量上的公共访问器.如果您不希望其他程序修改集合,那么 #2 和/或 #3 更好.

Maybe it just depends. If you don't care that the collection is modified, then just expose it as a public accessor over a private variable per #1. If you don't want other programs to modify the collection then #2 and/or #3 is better.

问题中隐含的是为什么应该使用一种方法而不是另一种方法,对安全性、内存、序列化等有什么影响?

Implicit in the question is why should one method be used over another and what are the ramifications on security, memory, serialization, etc.?

推荐答案

公开集合的方式完全取决于用户打算如何与之交互.

How you expose a collection depends entirely on how users are intended to interact with it.

1) 如果用户要从对象的集合中添加和删除项目,那么最好使用简单的仅获取集合属性(原始问题中的选项 1):

1) If users will be adding and removing items from an object's collection, then a simple get-only collection property is best (option #1 from the original question):

private readonly Collection<T> myCollection_ = new ...;
public Collection<T> MyCollection {
  get { return this.myCollection_; }
}

此策略用于 WindowsForms 和 WPF ItemsControl 控件上的 Items 集合,用户可以在其中添加和删除他们希望控件显示的项目.这些控件发布实际集合并使用回调或事件侦听器来跟踪项目.

This strategy is used for the Items collections on the WindowsForms and WPF ItemsControl controls, where users add and remove items they want the control to display. These controls publish the actual collection and use callbacks or event listeners to keep track of items.

WPF 还公开了一些可设置的集合,以允许用户显示他们控制的项目集合,例如 ItemsControl 上的 ItemsSource 属性(原始问题中的选项 #3).然而,这不是一个常见的用例.

WPF also exposes some settable collections to allow users to display a collection of items they control, such as the ItemsSource property on ItemsControl (option #3 from the original question). However, this is not a common use case.


2) 如果用户只会读取对象维护的数据,那么您可以使用只读集合,如 狡辩 建议:


2) If users will only be reading data maintained by the object, then you can use a readonly collection, as Quibblesome suggested:

private readonly List<T> myPrivateCollection_ = new ...;
private ReadOnlyCollection<T> myPrivateCollectionView_;
public ReadOnlyCollection<T> MyCollection {
  get {
    if( this.myPrivateCollectionView_ == null ) { /* lazily initialize view */ }
    return this.myPrivateCollectionView_;
  }
}

请注意,ReadOnlyCollection 提供了底层集合的实时视图,因此您只需创建一次视图.

Note that ReadOnlyCollection<T> provides a live view of the underlying collection, so you only need to create the view once.

如果内部集合没有实现IList,或者如果您想限制对更高级用户的访问,您可以改为通过枚举器包装对集合的访问:

If the internal collection does not implement IList<T>, or if you want to restrict access to more advanced users, you can instead wrap access to the collection through an enumerator:

public IEnumerable<T> MyCollection {
  get {
    foreach( T item in this.myPrivateCollection_ )
      yield return item;
  }
}

这种方法实现起来很简单,而且还提供了对所有成员的访问,而无需暴露内部集合.但是,它确实要求集合保持未修改状态,因为如果您在修改后尝试枚举集合,BCL 集合类将抛出异常.如果基础集合可能会更改,您可以创建一个轻量级包装器来安全地枚举集合,或者返回该集合的副本.

This approach is simple to implement and also provides access to all the members without exposing the internal collection. However, it does require that the collection remain unmodfied, as the BCL collection classes will throw an exception if you try to enumerate a collection after it has been modified. If the underlying collection is likely to change, you can either create a light wrapper that will enumerate the collection safely, or return a copy of the collection.


3) 最后,如果您需要公开数组而不是更高级别的集合,那么您应该返回数组的副本以防止用户修改它(原始问题中的选项 #2):


3) Finally, if you need to expose arrays rather than higher-level collections, then you should return a copy of the array to prevent users from modifying it (option #2 from the orginal question):

private T[] myArray_;
public T[] GetMyArray( ) {
  T[] copy = new T[this.myArray_.Length];
  this.myArray_.CopyTo( copy, 0 );
  return copy;
  // Note: if you are using LINQ, calling the 'ToArray( )' 
  //  extension method will create a copy for you.
}

您不应通过属性公开底层数组,因为您将无法判断用户何时修改它.要允许修改数组,您可以添加相应的 SetMyArray( T[] array ) 方法,或使用自定义索引器:

You should not expose the underlying array through a property, as you will not be able to tell when users modify it. To allow modifying the array, you can either add a corresponding SetMyArray( T[] array ) method, or use a custom indexer:

public T this[int index] {
  get { return this.myArray_[index]; }
  set {
    // TODO: validate new value; raise change event; etc.
    this.myArray_[index] = value;
  }
}

(当然,通过实现自定义索引器,您将重复 BCL 类的工作:)

(of course, by implementing a custom indexer, you will be duplicating the work of the BCL classes :)

这篇关于如何公开集合属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆