在C#泛型之前,每个人都会通过创建实现IEnumerable的集合库来为其业务对象编写集合
IE:
public class CollectionBase : IEnumerable
然后从中派生出他们的业务对象集合。
public class BusinessObjectCollection : CollectionBase
现在使用通用列表类,是否有人只使用它?我发现我使用了两种技术的折衷方案:
public class BusinessObjectCollection : List<BusinessObject>
我这样做是因为我喜欢使用强类型名称,而不是仅仅传递列表。
什么是你的方法?
答案 0 :(得分:49)
我一般都在直接使用List的阵营,除非由于某种原因我需要封装数据结构并提供其功能的有限子集。这主要是因为如果我没有特定的封装需求,那么这样做只是浪费时间。
但是,使用C#3.0中的聚合初始化功能,我会提倡使用自定义集合类的一些新情况。
基本上,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}
}
如果您需要创建复杂对象的静态表,这可能非常有用。例如,如果您只是使用List<Customer>
并且想要创建客户对象的静态列表,则必须如此创建它:
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"}
}
这样做的好处是更容易键入和更容易阅读,因为它们不需要为每个元素重新键入元素类型名称。如果元素类型长或复杂,则优点可以特别强。
话虽如此,只有在您需要在应用中定义的静态数据集时,这才有用。某些类型的应用程序(如编译器)会一直使用它们。其他人,如典型的数据库应用程序,不会因为他们从数据库加载所有数据。
我的建议是,如果您需要定义静态对象集合,或者需要封装集合接口,则创建自定义集合类。否则我会直接使用List<T>
。
答案 1 :(得分:14)
公共API中的recommended不使用List&lt; T&gt;,而是使用Collection&lt; T&gt;
如果你继承它,那你就没事了。
答案 2 :(得分:9)
我更喜欢使用List<BusinessObject>
。键入它只是为代码添加了不必要的样板。 List<BusinessObject>
是一种特定类型,它不仅仅是任何List
个对象,因此它仍然是强类型的。
更重要的是,声明某些内容List<BusinessObject>
可让所有阅读代码的人更容易分辨他们正在处理的内容,他们无需搜索以确定BusinessObjectCollection
是什么,然后记住它只是一个列表。通过typedefing,您必须要求每个人都必须遵循一致的(重新)命名约定才能使其有意义。
答案 3 :(得分:4)
我一直在两个选项上来回走动:
public class BusinessObjectCollection : List<BusinessObject> {}
或仅执行以下操作的方法:
public IEnumerable<BusinessObject> GetBusinessObjects();
第一种方法的好处是您可以更改基础数据存储而不必弄乱方法签名。不幸的是,如果你从一个从前一个实现中删除方法的集合类型继承,那么你将不得不在整个代码中处理这些情况。
答案 4 :(得分:4)
使用类型List<BusinessObject>
,您必须在其中声明它们的列表。然而,
在您返回BusinessObject
列表的位置,请考虑返回IEnumerable<T>
,IList<T>
或ReadOnlyCollection<T>
- 即返回满足客户的最弱的合同。
您要在列表中“添加自定义代码”的位置,列表类型上的代码扩展方法。再次,将这些方法附加到最弱的合同上,例如
public static int SomeCount(this IEnumerable<BusinessObject> someList)
当然,您不能也不应该使用扩展方法添加状态,因此如果您需要在其后面添加新属性和字段,请使用子类或更好的包装类来存储它。
答案 5 :(得分:3)
您应该避免为此目的创建自己的集合。在重构期间或添加新功能时,想要多次更改数据结构的类型是很常见的。使用您的方法,您将最终使用BusinessObjectList,BusinessObjectDictionary,BusinessObjectTree等单独的类。
我真的没有看到创建这个类的任何价值,因为classname更具可读性。是的,尖括号语法有点难看,但它在C ++,C#和Java中是标准的,所以即使你不编写使用它的代码,你也会一直遇到它。
答案 6 :(得分:2)
我和乔纳森完全一样......只是继承自List<T>
。你可以获得两全其美的效果。但是我通常只在有一些值要添加时才这样做,比如添加LoadAll()
方法或其他什么。
答案 7 :(得分:2)
您可以同时使用两者。对于懒惰 - 我的意思是生产力 - 列表是一个非常有用的类,它也是“全面的”,并且坦率地充满了YANGNI成员。加上MSDN article提出的合理的论点/建议已经与将List作为公共成员公开有关,我更喜欢“第三”方式:
我个人使用装饰器模式只显示我需要的List,即:
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实现(我可能更喜欢使用不同的内部可枚举对象,如Collection或者更多,因为perf使用键值对收集或设置。
答案 8 :(得分:2)
如果我需要“增值”,我通常只派生自己的集合类。就像,如果集合本身需要一些“元数据”属性标记它。
答案 9 :(得分:1)
我几乎在所有场景中使用通用列表。我不再考虑使用派生集合的唯一一次是添加特定于集合的成员。然而,LINQ的出现减少了对它的需求。
答案 10 :(得分:0)
6个中的6个,另外6个
无论哪种方式都是一样的。我只有在有理由将自定义代码添加到BusinessObjectCollection时才这样做。
如果没有加载方法返回,列表允许我在一个通用泛型类中编写更多代码并使其正常工作。比如一个Load方法。
答案 11 :(得分:0)
正如其他人指出的那样,建议不要公开公开List,如果你这样做,FxCop会发牢骚。这包括从List继承,如下所示:
public MyTypeCollection : List<MyType>
在大多数情况下,公共API将根据需要公开IList(或ICollection或IEnumerable)。
如果您需要自己的自定义集合,可以通过继承Collection而不是List来保持FxCop的安静。
答案 12 :(得分:0)
如果您选择创建自己的集合类,则应查看System.Collections.ObjectModel Namespace中的类型。
命名空间定义基类,使实现者更容易创建自定义集合。
答案 13 :(得分:0)
如果我想屏蔽对实际列表的访问,我倾向于使用我自己的集合。当你编写业务对象时,你可能需要一个钩子来知道你的对象是否被添加/删除,从这个意义上来说我认为BOCollection是更好的主意。如果不需要,那么List更轻量级。如果您需要某种代理(例如,假集合触发来自数据库的延迟加载),您可能还需要使用IList检查以提供额外的抽象接口
但是......为什么不考虑Castle ActiveRecord或任何其他成熟的ORM框架? :)
答案 14 :(得分:0)
在大多数情况下,我只是采用List方式,因为它在90%的时间内为我提供了所需的所有功能,当需要“额外”的东西时,我继承了它,并且代码额外的一点。
答案 15 :(得分:0)
我会这样做:
using BusinessObjectCollection = List<BusinessObject>;
这只是创建一个别名而不是一个全新的类型。我更喜欢使用List&lt; BusinessObject&gt;直接因为它让我可以在将来某个时候自由地更改集合的底层结构而不更改使用它的代码(只要我提供相同的属性和方法)。
答案 16 :(得分:0)
试试这个:
System.Collections.ObjectModel.Collection<BusinessObject>
它没有必要实现像CollectionBase do
这样的基本方法答案 17 :(得分:-1)
这是方式:
返回数组,接受IEnumerable<T>
=)