在 C# 泛型出现之前,每个人都会通过创建实现 IEnumerable 的集合基来为其业务对象编写集合代码

IE:

public class CollectionBase : IEnumerable

然后从中派生出他们的业务对象集合。

public class BusinessObjectCollection : CollectionBase

现在有了通用列表类,有人直接使用它吗?我发现我使用了两种技术的折衷方案:

public class BusinessObjectCollection : List<BusinessObject>

我这样做是因为我喜欢使用强类型名称,而不是仅仅传递列表。

什么是 你的 方法?

有帮助吗?

解决方案

我通常倾向于直接使用列表,除非由于某种原因我需要封装数据结构并提供其功能的有限子集。这主要是因为如果我没有特定的封装需求那么这样做只是浪费时间。

然而,随着 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> 直接地。

其他提示

它是 受到推崇的 在公共 API 中不要使用 List<T>,而是使用 Collection<T>

如果你继承它,你应该没问题,afaik。

我更喜欢只使用 List<BusinessObject>. 。类型定义只是在代码中添加了不必要的样板。 List<BusinessObject> 是一个特定的类型,它不仅仅是任何类型 List 对象,所以它仍然是强类型的。

更重要的是,声明一些东西 List<BusinessObject> 让每个阅读代码的人都更容易知道他们正在处理什么类型,他们不必通过搜索来找出什么是 BusinessObjectCollection 是,然后记住这只是一个列表。通过类型定义,您必须要求每个人都必须遵循一致的(重新)命名约定才能使其有意义。

使用类型 List<BusinessObject> 您必须在其中声明它们的列表。然而 返回一个 BusinessObject, ,考虑返回 IEnumerable<T>, IList<T> 或者 ReadOnlyCollection<T> - IE。返回令客户满意的最弱的合约。

如果您想要“添加自定义代码”到列表,请在列表类型上编写代码扩展方法。再次,将这些方法附加到最弱的可能合约上,例如

public static int SomeCount(this IEnumerable<BusinessObject> someList)

当然,您不能也不应该使用扩展方法添加状态,因此如果您需要添加新属性及其后面的字段,请使用子类或更好的包装类来存储它。

我一直在考虑两个选择:

public class BusinessObjectCollection : List<BusinessObject> {}

或只执行以下操作的方法:

public IEnumerable<BusinessObject> GetBusinessObjects();

第一种方法的好处是您可以更改底层数据存储,而不必弄乱方法签名。不幸的是,如果您继承的集合类型从先前的实现中删除了方法,那么您将必须在整个代码中处理这些情况。

您可能应该避免为此目的创建自己的集合。在重构或添加新功能时想要多次更改数据结构的类型是很常见的。通过您的方法,您最终会得到一个单独的 BusinessObjectList、BusinessObjectDictionary、BusinessObjectTree 等类。

我并没有真正看到创建此类的任何价值,只是因为类名更具可读性。是的,尖括号语法有点难看,但它是 C++、C# 和 Java 中的标准,因此即使您不编写使用它的代码,您也会一直遇到它。

我通常只在需要“增值”时派生自己的集合类。例如,如果集合本身需要一些“元数据”属性标记。

我和你做的事情一模一样,乔纳森......只是继承自 List<T>. 。您将获得两全其美的效果。但我通常只在需要添加一些价值时才这样做,例如添加 LoadAll() 方法或者什么。

您可以同时使用两者。对于懒惰 - 我的意思是生产力 - List 是一个非常有用的类,它也是“全面的”并且坦率地说充满了 YANGNI 成员。加上提出的合理论点/建议 MSDN 文章 已经链接了有关将 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 或更喜欢使用键值对集合或 Set 。

我对几乎所有场景都使用通用列表。我唯一会考虑使用派生集合的情况是添加集合特定成员。然而,LINQ 的出现甚至减少了这种需求。

1 个中的 6 个,另外 6 个

无论哪种方式都是一样的。仅当我有理由将自定义代码添加到 BusinessObjectCollection 中时,我才会这样做。

如果没有它,加载方法会返回一个列表,这样我就可以在通用泛型类中编写更多代码并使其正常工作。比如Load方法。

正如其他人指出的那样,建议不要公开暴露 List,如果这样做,FxCop 会抱怨的。这包括从 List 继承,如下所示:

public MyTypeCollection : List<MyType>

在大多数情况下,公共 API 将根据需要公开 IList(或 ICollection 或 IEnumerable)。

如果您想要自己的自定义集合,可以通过继承 Collection 而不是 List 来保持 FxCop 安静。

如果您选择创建自己的集合类,您应该检查以下类型 System.Collections.ObjectModel 命名空间.

命名空间定义了基类,这些基类使实现者更容易创建自定义集合。

如果我想屏蔽对实际列表的访问,我倾向于使用我自己的集合来完成此操作。当您编写业务对象时,您可能需要一个钩子来知道您的对象是否被添加/删除,从这个意义上说,我认为 BOCollection 是更好的主意。当然,如果不需要的话,List 更轻量。另外,如果您需要某种代理(例如,假集合会触发数据库的延迟加载)

但...为什么不考虑 Castle ActiveRecord 或任何其他成熟的 ORM 框架?:)

大多数时候,我只是使用 List 方式,因为它在 90% 的时间里为我提供了我需要的所有功能,当需要“额外”的东西时,我继承它,并编写额外的位。

我会这样做:

using BusinessObjectCollection = List<BusinessObject>;

这只是创建一个别名而不是一个全新的类型。与直接使用 List<BusinessObject> 相比,我更喜欢它,因为它使我可以在将来的某个时刻自由地更改集合的底层结构,而无需更改使用它的代码(只要我提供相同的属性和方法)。

试试这个:

System.Collections.ObjectModel.Collection<BusinessObject>

不需要像 CollectionBase 那样实现基本方法

就是这样:

返回数组,接受 IEnumerable<T>

=)

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top