使用IEnumerator和使用数组作为属性的区别

问题描述 投票:1回答:2

我明白了IEnumerator的概念,它给了一个类迭代的能力。我知道为什么GetEnumerable()需要使用foreach语句。但我想知道为什么我需要实现IEnumerator,而我可以声明一个数组作为一个属性?我真的很困惑,需要一个好的解释。这是我的代码块,实现了IEnumerator和没有实现IEnumerator的结果是一样的。

static void Main(string[] args)
    {

        Customer customer1 = new Customer
        {
            Name = "Marty",
            Surname = "Bird",
            Id = 1
        };
        Customer customer2 = new Customer
        {
            Name = "Hellen",
            Surname = "Pierce",
            Id = 2
        };
        Customers customers = new Customers();
        customers.Add(customer1);
        customers.Add(customer2);
        //Using a property: This one works without an extra GetEnumerator implementation.
        foreach (var item in customers.CustomerList)
        {
            Console.WriteLine(item.Name);
        }
        //Using with GetEnumerator()
        foreach (Customer item in customers)
        {
            Console.WriteLine(item.Name);
        }

    }
    class Customer
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Surname { get; set; }
    }

    class Customers:IEnumerable
    {
        private List<Customer> customerList = new List<Customer>();

        public List<Customer> CustomerList { get=> customerList; }
        public void Add(Customer p)
        {
            customerList.Add(p);
        }

        public IEnumerator GetEnumerator()
        {
            return customerList.GetEnumerator();
        }
    }
c# arrays .net implementation ienumerator
2个回答
3
投票

你真的完全不需要实现IEnumerator。你可以把Customers类去掉,然后把这一行替换成:"Customers"。

Customers customers = new Customers();

用这个来代替。

List<Customer> customers = new List<Customers>();

你被要求实现GetEnumerator的唯一原因是因为你从IEnumerable继承了Customers类,而IEnumerable是一个声明该方法的接口。一个接口中的所有方法和属性必须在实现该接口的类中实现。

只是鉴于你所展示的代码,你不需要Customers类,只要按照我上面的解释使用List即可。

然而,如果你真的需要一个Customers类,因为你打算在它上面添加比你所展示的更多的功能,一个选择是继承自于 List<Customer>. 那么在foreach语句中就可以工作,而不需要实现GetEnumerable(),因为List已经实现了该方法。


2
投票

数组属性经常会引起错误。我们开发一个可靠的数组属性,以避免foreach-循环中的错误。微软提出了一种设计模式,即使没有数据,也不使用空值。

class Program
{
    static void Main()
    {
        foreach (string item in Empty)
        {
            System.Console.WriteLine(item); // Never reached
        }
    }

    /// Get an empty array.
    public static string[] Empty
    {
        get
        {
            return new string[0]; // Won't crash in foreach
        }
    }
}

在.NET中,它的IEnumerable接口命名错误--应该是IIterable。基本上,一个System.Collection.IEnumerable或(因为是通用的)System.Collection.Generic.IEnumerable允许你在实现这些接口的对象上使用foreach.IEnumerable,另一方面,基本上说给定一个起始位置就可以得到下一个值。一个例子可能是一个无限的数字系列。

public IEnumerable<int> Infinite()
{
    int i = 0;
    while(true)
        yield return i++;
}

1
投票

这是因为一个数组实现了 GetEnumerator(). 不过你的类可能并不总是在一个已经为你实现的数据结构中存储可枚举的东西。你可以很有创意,因为这种模式非常灵活。

以这个类为例。

class Numbers1To5 : IEnumerable<int>
{
    public IEnumerator<int> GetEnumerator() => new Numbers1To5Enumerator();

    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

    class Numbers1To5Enumerator : IEnumerator<int>
    {
        public int Current { get; private set; }
        object IEnumerator.Current => Current;

        public bool MoveNext()
        {
            if (Current >= 5)
                return false;

            Current++;

            return true;
        }

        public void Reset()
        {
            Current = 0;
        }

        public void Dispose()
        {
        }
    }
}

如果你有一个程序,做了下面的事情, 你会得到在控制台中显示的数字1到5。

foreach (int number in new Numbers1To5())
    Console.WriteLine(number);

1
投票

如果你想滚动你自己的枚举式程序 Customers 类,很容易。

class Customers : List<Customer>
{
}

就是这样!

现在你可以这样做了。

Customer customer1 = new Customer
{
    Name = "Marty",
    Surname = "Bird",
    Id = 1
};
Customer customer2 = new Customer
{
    Name = "Hellen",
    Surname = "Pierce",
    Id = 2
};
Customers customers = new Customers();
customers.Add(customer1);
customers.Add(customer2);
foreach (var item in customers)
{
    Console.WriteLine(item.Name);
}

说到这里,你可能会想读一下这个答案。创建你自己的集合类是个好做法吗?. 在大多数情况下,你可以跳过这个特殊的类,直接使用 List<Customer> 直接。

© www.soinside.com 2019 - 2024. All rights reserved.