列出<BusinessObject>或BusinessObjectCollection?
在C#generics之前,每个人都可以通过创build一个实现了IEnumerable的集合库来为他们的业务对象编写集合
IE:
public class CollectionBase : IEnumerable
然后从中得到他们的业务对象集合。
public class BusinessObjectCollection : CollectionBase
现在用generics列表类,没有人只是使用它呢? 我发现我使用这两种技术的妥协:
public class BusinessObjectCollection : List<BusinessObject>
我这样做是因为我喜欢强types名称,而不是仅仅传递List。
你的方法是什么?
我通常在直接使用List的阵营,除非由于某种原因,我需要封装数据结构,并提供其function的有限子集。 这主要是因为如果我没有特殊的封装需求,那么这样做只是浪费时间。
但是,使用C#3.0中的聚合初始化function,我会提倡使用自定义集合类的一些新情况。
基本上,C#3.0允许任何实现了IEnumerable
类,并且有一个Add方法来使用新的聚集初始化语法。 例如,因为Dictionary定义了一个方法Add(K key,V value),所以可以用下面的语法初始化一个字典:
var d = new Dictionary<string, int> { {"hello", 0}, {"the answer to life the universe and everything is:", 42} };
关于这个特性的好处是,它可以用于任意数量参数的添加方法。 例如,给定这个集合:
class c1 : IEnumerable { void Add(int x1, int x2, int x3) { //... } //... }
可以像这样初始化它:
var x = new c1 { {1,2,3}, {4,5,6} }
如果您需要创build复杂对象的静态表,这可能非常有用。 例如,如果您只是使用List<Customer>
并且想要创build一个客户对象的静态列表,则必须像这样创build它:
var x = new List<Customer> { new Customer("Scott Wisniewski", "555-555-5555", "Seattle", "WA"), new Customer("John Doe", "555-555-1234", "Los Angeles", "CA"), new Customer("Michael Scott", "555-555-8769", "Scranton PA"), new Customer("Ali G", "", "Staines", "UK") }
但是,如果您使用自定义集合,如下所示:
class CustomerList : List<Customer> { public void Add(string name, string phoneNumber, string city, string stateOrCountry) { Add(new Customer(name, phoneNumber, city, stateOrCounter)); } }
您可以使用以下语法初始化集合:
var customers = new CustomerList { {"Scott Wisniewski", "555-555-5555", "Seattle", "WA"}, {"John Doe", "555-555-1234", "Los Angeles", "CA"}, {"Michael Scott", "555-555-8769", "Scranton PA"}, {"Ali G", "", "Staines", "UK"} }
这样做的好处是既易于input又易于阅读,因为它们不需要为每个元素重新input元素types名称。 如果元素types长或复杂,则优点可以特别强。
这就是说,只有当你需要在你的应用程序中定义的静态数据集时,这才是有用的。 某些types的应用程序(如编译器)始终使用它们。 其他的,像典型的数据库应用程序不会因为他们加载数据库中的所有数据。
我的build议是,如果你需要定义一个静态的对象集合,或者需要封装集合接口,那么创build一个自定义集合类。 否则,我会直接使用List<T>
。
build议在公共API中不要使用List <T>,而要使用Collection <T>
如果你从它inheritance,你应该没问题,afaik。
我宁愿只使用List<BusinessObject>
。 键入它只是给代码添加了不必要的样板。 List<BusinessObject>
是一个特定的types,它不仅仅是任何List
对象,所以它仍然是强types的。
更重要的是,声明List<BusinessObject>
使每个读取代码的人都可以更容易地知道他们正在处理的是哪些types,他们不需要search以找出BusinessObjectCollection
是什么,然后记住它只是一个列表。 通过typedefing,你必须要求一个一致的(重新)命名约定,每个人都必须遵循才能使其有意义。
使用typesList<BusinessObject>
,您必须声明它们的列表。 但是,如果返回BusinessObject
列表,请考虑返回IEnumerable<T>
, IList<T>
或ReadOnlyCollection<T>
– 即返回满足客户端的最弱可能合约。
您想在列表中添加自定义代码的位置,列表types上的代码扩展方法。 再次,将这些方法附加到最弱的合同,例如
public static int SomeCount(this IEnumerable<BusinessObject> someList)
当然,你不能也不应该用扩展方法添加状态,所以如果你需要添加一个新的属性和后面的字段,使用一个子类或更好的包装类来存储这个。
我一直在两个选项之间来回走动:
public class BusinessObjectCollection : List<BusinessObject> {}
或者只是执行以下操作的方法:
public IEnumerable<BusinessObject> GetBusinessObjects();
第一种方法的好处是,您可以更改底层数据存储,而不必混淆方法签名。 不幸的是,如果你从一个集合typesinheritance,那么这个集合types会从前面的实现中移除一个方法,那么你将不得不在整个代码中处理这些情况。
您应该避免为此目的创build自己的集合。 在重构过程中或者在添加新的特性时,想要多次改变数据结构的types是很常见的。 通过您的方法,您可以为BusinessObjectList,BusinessObjectDictionary,BusinessObjectTree等单独分类。
我真的没有看到创build这个类的任何价值,因为类名更具可读性。 是的,尖括号的语法是丑陋的,但它是C ++,C#和Java的标准,所以即使你不写代码使用它,你会一直运行它。
我做的和Jonathan完全一样…只是从List<T>
inheritance。 你得到两全其美。 但是我通常只在添加一些值的时候才会这样做,比如添加一个LoadAll()
方法等等。
如果我需要“增加价值”,我通常只会派生自己的集合类。 就像,如果集合本身需要有一些“元数据”属性标记。
你可以使用两者。 对于懒惰 – 我的意思是生产力 – 列表是一个非常有用的类,它也是“全面的”,并坦率地充满了YANGNI成员。 再加上MSDN文章中提出的关于公开成员暴露List的明智论据/build议,我更喜欢“第三种”方式:
就我个人而言,我使用装饰模式,只暴露我需要从列表即:
public OrderItemCollection : IEnumerable<OrderItem> { private readonly List<OrderItem> _orderItems = new List<OrderItem>(); void Add(OrderItem item) { _orderItems.Add(item) } //implement only the list members, which are required from your domain. //ie. sum items, calculate weight etc... private IEnumerator<string> Enumerator() { return _orderItems.GetEnumerator(); } public IEnumerator<string> GetEnumerator() { return Enumerator(); } }
更进一步,我可能会抽象OrderItemCollection到IOrderItemCollection,所以我可以交换IOrderItemCollection在未来的实现(我可能更喜欢使用不同的内部可枚举对象,如集合或更喜欢使用一个键值对集合或集。
几乎所有的场景都使用generics列表。 我只考虑使用派生集合的唯一时间是如果我添加特定于集合的成员。 然而,LINQ的出现减less了甚至需要。
1,6,6,另一半
无论哪种方式是同样的事情。 我只有当我有理由将自定义代码添加到BusinessObjectCollection时才这样做。
没有它的加载方法返回一个列表允许我写一个共同的generics类更多的代码,并只是工作。 比如一个Load方法。
正如别人指出的那样,build议不要公开暴露列表,如果你这样做,FxCop会鸣叫。 这包括从Listinheritance,如下所示:
public MyTypeCollection : List<MyType>
在大多数情况下,公共API将酌情公开IList(或ICollection或IEnumerable)。
如果你想要自己的自定义集合,可以通过从Collection而不是List来inheritanceFxCop。
如果您select创build自己的集合类,则应该检出System.Collections.ObjectModel Namespace中的types。
命名空间定义了基类,使实现者更容易创build自定义集合。
如果我想屏蔽实际列表的访问权限,我倾向于使用我自己的collections集。 当你写业务对象的时候,很有可能你需要一个钩子来知道你的对象是被添加还是删除了,这样的话我觉得BOCollection是个好主意。 如果不需要的话,List是更轻量级的。 另外,如果您需要某种代理(例如,假集合触发数据库的延迟加载),则可能需要检查使用IList来提供更多的抽象接口,
但是…为什么不考虑Castle ActiveRecord或任何其他成熟的ORM框架? 🙂
在大多数情况下,我只需要使用List方法,因为它在90%的时间内为我提供了所需的所有function,当需要“额外”时,我从它inheritance,然后编写额外的位。
我会这样做:
using BusinessObjectCollection = List<BusinessObject>;
这只是创build一个别名,而不是一个全新的types。 我更喜欢直接使用List <BusinessObject>,因为它使我可以在将来的某个时候自由地更改集合的底层结构,而不必更改使用它的代码(只要我提供相同的属性和方法)即可。
试试这个:
System.Collections.ObjectModel.Collection<BusinessObject>
不需要像CollectionBase那样实现基本的方法
这是方式:
返回数组,接受IEnumerable<T>
=)