Implementing IEnumerable, Lists

本文关键字:Lists IEnumerable Implementing | 更新日期: 2023-09-27 17:50:40

我找到了这个MSDN教程

它描述了实现IEnumerable以便在foreach循环中使用对象。我的问题是,在示例的主要方法中,它使用Person数组来初始化People class。我可以使用List< ClientEntry>而不是ClientEntry的数组吗?为某个类实现List需要什么?

Implementing IEnumerable, Lists

List<T>的文档中可以看到,该类具有签名:

[SerializableAttribute]
[DebuggerDisplayAttribute("Count = {Count}")]
public class List<T> : IList<T>, ICollection<T>, 
    IEnumerable<T>, IEnumerable, IList, ICollection, IReadOnlyList<T>, 
    IReadOnlyCollection<T>

可以看到,它已经实现了IEnumerable<T>IEnumerable。这意味着每个List<T>实例都可以在foreach循环中使用:

List<Person> people = new List<Person>();
//add people
foreach(Person p in people) {
}

此外,T没有限制(您可以使用任何您喜欢的类型)。否则签名应该包含

public class OtherList<T> : IEnumerable<T> where T : class

where T : ...表示T应该满足某个约束。根本不需要自己开始实现List<T>

List<T>class。由于c#不允许多重继承,因此只能通过添加继承:

来使Peolpe成为List<People>的元素。
// Collection of Person objects. This class 
// implements IEnumerable so that it can be used 
// with ForEach syntax. 
public class People : List<Person> {
    public People(Person[] pArray) {
        this.AddRange(pArray);
    }
}

在这种情况下,您不需要实现IEnumerable<T>和其他接口。但只有当你想添加额外的行为(或修改一些行为),没有理由使用People而不是List<Person>

当然可以使用List<Person>而不是Person[]。您只需要替换所有的支持变量,将它们的类型从array更改为List,并更改相关代码。然而,关键是List已经是可枚举的,所以使用List作为内部存储实现另一个IEnumerable没有多大意义,除非您正在做一些特殊的事情,如基于动态条件跳过某些元素等。

您不需要创建自定义集合来在列表中使用类。已经有一个现成的泛型集合,可以用于任何类(通过泛型)。

你现在可以这样做,

[Flags()]
public enum AddressTypeValue : ushort
{
    Personal = 0,
    Business = 1,
    POBox = 2,
    Inertnational = 4
}
public class Address
{
    public AddressTypeValue AddressType { get; set; }
}
public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public Address Address { get; set; }
    public Person() 
    {
        Address = new Address() { AddressType == AddressTypeValue.Personal };
    }
}

//一些在列表中使用它的代码

List<Person> people = new List<Person>();
public List<Person> GetPeopleMatchingFirstName(string firstNameToMatch)
{
    var people = DBContext.People.Where(p => p.FirstName.BegintsWith(firstNameToMatch) || p.FirstName.EndsWith(firstNameToMatch) || p.FirstName.Equals(firstNameToMatch, StringComparison.InvariantCultureIgnoreCase);
    return people.ToList();
}

现在,如果你想要一个强类型集合,你想要有自定义逻辑的添加/删除/插入/索引等,那么,只有这样,你才需要实现IList或IEnumerable。

有更简单的方法可以做到这一点,因为您只需通过继承实现List并覆盖您想要更改的内容。如果你想改变的行为不是虚拟的(不能被覆盖),那么你可能需要List的自定义实现。

public class MyCustomListOfPeople : List<Person>
{
    public override Add(Person person)
    {
        //send email that a person was added or w/e you want to do here
        base.Add(person);
    }
}

如果你想要一个只读列表,其中的东西不能被添加,那么你可以使用ReadOnlyCollection,你传入一个基本列表。一旦构造,就不能从ReadOnlyCollection中添加或删除任何内容。这对于诸如州列表、邮政编码、报告数据等内容非常有用。

包装List并将其暴露为IEnumerable也很容易,而不允许访问它的add/delete等方法。

public class AnotherListOfPeople : IEnumerable<Person>
{
    private List<Person> internalList = new List<Person>();
    //internal logic to manipulate people
    public IEnumerator<Person> GetEnumerator()
    {
        return internalList.GetEnumerator();
    }
    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return internalList.GetEnumerator();
    }
}

执行后一种操作允许您将私有列表的内置枚举器暴露给其他东西。因此,枚举器接口由包装类公开,这些接口允许您的类使用Linq和foreach进行枚举,同时阻止调用者直接访问List。

有很多方法可以利用List或IEnumerable的功能,但一般来说,您可以使用List来满足您的需要,很少需要包装List或实现自定义集合的接口。