【问题标题】:Implementing IEnumerable, Lists实现 IEnumerable、列表
【发布时间】:2015-05-26 02:24:31
【问题描述】:

我找到this MSDN tutorial

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

【问题讨论】:

  • List<People> 已经实现了 IEnumerable,所以不需要你自己实现。
  • 所以我可以使用 People in list 的编写方式了吗?
  • 如果您是这个意思,您已经可以使用带有List<People> 的 foreach。
  • 我真正要问的是,在 List、Dict 等中使用类是否有一定的要求?或者这并不重要。例如,Person 是业务对象,People 只是一个实现 IEnumerable 的人员数组 我可以将 Person 用于列表吗?在那种情况下,如果我只能使用 List,那么将 People 实现为 IEnumerable 有什么意义?
  • 我建议在询问 SO 时一次只回答一个问题。 “我可以使用List<Person> 而不是Person[] 来实现可枚举”似乎足够合理。问你为什么会选择一种方法而不是另一种方法通常会被证明是基于意见的问题,因此会被关闭......

标签: c# list ienumerable


【解决方案1】:

正如在有关List<T> 的文档中看到的那样,此类具有签名:

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

如您所见,它已经实现了IEnumerable&lt;T&gt;IEnumerable。这意味着每个List&lt;T&gt; 实例都可以在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&lt;T&gt;s。

List&lt;T&gt;class。由于 C# 不允许多重继承,因此只能通过添加继承使 Peolpe 成为 List&lt;People&gt; 的元素:

// 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&lt;T&gt; 和其他接口。但只有当您想添加其他行为(或修改某些行为)时,才没有理由使用 People 而不是 List&lt;Person&gt;

【讨论】:

【解决方案2】:

当然可以使用List&lt;Person&gt; 代替Person[]。您只需要替换所有支持变量,将它们的类型从数组更改为列表并更改相关代码。然而,关键是 List 已经是可枚举的,因此使用 List 作为内部存储来实现另一个 IEnumerable 没有多大意义,除非你正在做一些特殊的事情,比如根据动态条件跳过某些元素等。

【讨论】:

  • 我不知道我的英语是否正确,但是当你说“当然可以”时,我觉得你从来没有做过,很难让它发挥作用,你建议反对。我建议使用“非常简单”这一短语,而不是“肯定有可能”,因为我认为这就是您所追求的感觉。
  • @Enigmativity 我的意思是完全有可能但不值得努力。你是对的,我从来没有这样做过。
【解决方案3】:

您无需创建自定义集合即可使用列表中的类。已经有一个开箱即用的泛型集合,可用于任何类(通过泛型)。

你现在可以这样做了,

[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 也很容易,而不允许访问它的添加/删除等方法。

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 或 IEnumerable 的强大功能,但通常您可以将 List 用于您需要的任何东西,而很少需要包装一个 List 或实现自定义集合的接口。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-12-04
    • 1970-01-01
    • 2020-10-13
    • 1970-01-01
    • 1970-01-01
    • 2021-07-28
    • 1970-01-01
    相关资源
    最近更新 更多