有人能给我解释一下IEnumerable和IEnumerator吗?
例如,什么时候用它胜过foreach?IEnumerable和IEnumerator的区别是什么?为什么我们需要使用它?
有人能给我解释一下IEnumerable和IEnumerator吗?
例如,什么时候用它胜过foreach?IEnumerable和IEnumerator的区别是什么?为什么我们需要使用它?
当前回答
IEnumerable和IEnumerator都是c#中的接口。
IEnumerable是一个接口,它定义了一个返回IEnumerator接口的方法GetEnumerator()。
这适用于对集合的只读访问,该集合实现了IEnumerable可与foreach语句一起使用。
IEnumerator有两个方法,MoveNext和Reset。它还有一个名为Current的属性。
下面展示了IEnumerable和IEnumerator的实现。
其他回答
IEnumerable和IEnumerator接口
在开始研究实现现有.NET接口的过程之前,让我们首先看看的角色 IEnumerable和IEnumerator。回想一下,c#支持名为foreach的关键字,它允许您这样做 遍历任意数组类型的内容:
// Iterate over an array of items.
int[] myArrayOfInts = {10, 20, 30, 40};
foreach(int i in myArrayOfInts)
{
Console.WriteLine(i);
}
虽然看起来只有数组类型可以使用这个构造,但事实是 任何支持名为GetEnumerator()方法的类型都可以由foreach构造求值。来 举例说明,跟我来!
假设我们有一个Garage类:
// Garage contains a set of Car objects.
public class Garage
{
private Car[] carArray = new Car[4];
// Fill with some Car objects upon startup.
public Garage()
{
carArray[0] = new Car("Rusty", 30);
carArray[1] = new Car("Clunker", 55);
carArray[2] = new Car("Zippy", 30);
carArray[3] = new Car("Fred", 30);
}
}
理想情况下,使用foreach迭代Garage对象的子项会很方便 构造,就像一个数据值数组一样:
// This seems reasonable ...
public class Program
{
static void Main(string[] args)
{
Console.WriteLine("***** Fun with IEnumerable / IEnumerator *****\n");
Garage carLot = new Garage();
// Hand over each car in the collection?
foreach (Car c in carLot)
{
Console.WriteLine("{0} is going {1} MPH",
c.PetName, c.CurrentSpeed);
}
Console.ReadLine();
}
}
不幸的是,编译器告诉您Garage类没有实现名为 GetEnumerator()。该方法由IEnumerable接口形式化,该接口隐藏在系统中。集合名称空间。 支持此行为的类或结构宣称它们能够公开所包含的内容 调用者的子项(在本例中为foreach关键字本身)。下面是这个标准。net接口的定义:
// This interface informs the caller
// that the object's subitems can be enumerated.
public interface IEnumerable
{
IEnumerator GetEnumerator();
}
如您所见,GetEnumerator()方法返回对另一个名为 System.Collections.IEnumerator。该接口提供了允许调用者遍历ienumerable兼容容器所包含的内部对象的基础结构:
// This interface allows the caller to
// obtain a container's subitems.
public interface IEnumerator
{
bool MoveNext (); // Advance the internal position of the cursor.
object Current { get;} // Get the current item (read-only property).
void Reset (); // Reset the cursor before the first member.
}
如果您想要更新Garage类型以支持这些接口,那么您可能要走很长的路 手动实现每个方法。当然,您可以自由地提供自定义版本的 GetEnumerator(), MoveNext(), Current和Reset(),有一个更简单的方法。作为系统。数组类型(以及许多其他集合类)已经实现了IEnumerable和IEnumerator,您可以简单地将请求委托给系统。数组如下:
using System.Collections;
...
public class Garage : IEnumerable
{
// System.Array already implements IEnumerator!
private Car[] carArray = new Car[4];
public Garage()
{
carArray[0] = new Car("FeeFee", 200);
carArray[1] = new Car("Clunker", 90);
carArray[2] = new Car("Zippy", 30);
carArray[3] = new Car("Fred", 30);
}
public IEnumerator GetEnumerator()
{
// Return the array object's IEnumerator.
return carArray.GetEnumerator();
}
}
更新车库类型之后,就可以在c# foreach构造中安全地使用该类型了。此外,假定GetEnumerator()方法是公开定义的,对象用户也可以与IEnumerator类型交互:
// Manually work with IEnumerator.
IEnumerator i = carLot.GetEnumerator();
i.MoveNext();
Car myCar = (Car)i.Current;
Console.WriteLine("{0} is going {1} MPH", myCar.PetName, myCar.CurrentSpeed);
但是,如果您希望从对象级别隐藏IEnumerable的功能,只需使 使用显式接口实现:
IEnumerator IEnumerable.GetEnumerator()
{
// Return the array object's IEnumerator.
return carArray.GetEnumerator();
}
通过这样做,临时对象用户将不会找到Garage的GetEnumerator()方法,而 Foreach构造将在必要时在后台获取接口。
改编自Pro c# 5.0和。net 4.5框架
IEnumerable是一个包含Ienumerator的框。IEnumerable是所有集合的基本接口。如果集合实现了IEnumerable,则foreach循环可以运行。在下面的代码中,它解释了拥有自己的枚举器的步骤。让我们首先定义我们要创建集合的Class。
public class Customer
{
public String Name { get; set; }
public String City { get; set; }
public long Mobile { get; set; }
public double Amount { get; set; }
}
现在我们将定义Class,它将作为我们的类Customer的集合。注意,它实现了接口IEnumerable。所以我们必须实现GetEnumerator方法。这将返回我们的自定义枚举器。
public class CustomerList : IEnumerable
{
Customer[] customers = new Customer[4];
public CustomerList()
{
customers[0] = new Customer { Name = "Bijay Thapa", City = "LA", Mobile = 9841639665, Amount = 89.45 };
customers[1] = new Customer { Name = "Jack", City = "NYC", Mobile = 9175869002, Amount = 426.00 };
customers[2] = new Customer { Name = "Anil min", City = "Kathmandu", Mobile = 9173694005, Amount = 5896.20 };
customers[3] = new Customer { Name = "Jim sin", City = "Delhi", Mobile = 64214556002, Amount = 596.20 };
}
public int Count()
{
return customers.Count();
}
public Customer this[int index]
{
get
{
return customers[index];
}
}
public IEnumerator GetEnumerator()
{
return customers.GetEnumerator(); // we can do this but we are going to make our own Enumerator
return new CustomerEnumerator(this);
}
}
现在我们要创建自己的自定义枚举器,如下所示。我们必须实现方法MoveNext。
public class CustomerEnumerator : IEnumerator
{
CustomerList coll;
Customer CurrentCustomer;
int currentIndex;
public CustomerEnumerator(CustomerList customerList)
{
coll = customerList;
currentIndex = -1;
}
public object Current => CurrentCustomer;
public bool MoveNext()
{
if ((currentIndex++) >= coll.Count() - 1)
return false;
else
CurrentCustomer = coll[currentIndex];
return true;
}
public void Reset()
{
// we dont have to implement this method.
}
}
现在我们可以像下面这样对我们的集合使用foreach循环;
class EnumeratorExample
{
static void Main(String[] args)
{
CustomerList custList = new CustomerList();
foreach (Customer cust in custList)
{
Console.WriteLine("Customer Name:"+cust.Name + " City Name:" + cust.City + " Mobile Number:" + cust.Amount);
}
Console.Read();
}
}
实现IEnumerable的对象允许其他人访问它的每一项(通过枚举器)。 实现IEnumerator的对象是在进行迭代。它循环遍历一个可枚举对象。
可以把可枚举对象想象成列表、堆栈、树。
例如,什么时候用它胜过foreach?
你不用IEnumerable "over" foreach。实现IEnumerable使得使用foreach成为可能。
当你写这样的代码时:
foreach (Foo bar in baz)
{
...
}
它在功能上相当于这样写:
IEnumerator bat = baz.GetEnumerator();
while (bat.MoveNext())
{
bar = (Foo)bat.Current
...
}
所谓“功能等效”,我指的是编译器实际将代码转换成的内容。在本例中,除非baz实现了IEnumerable,否则不能在baz上使用foreach。
IEnumerable表示baz实现了该方法
IEnumerator GetEnumerator()
该方法返回的IEnumerator对象必须实现这些方法
bool MoveNext()
and
Object Current()
第一个方法前进到创建枚举器的IEnumerable对象中的下一个对象,如果完成则返回false,第二个方法返回当前对象。
. net中任何你可以迭代的东西都实现了IEnumerable。如果您正在构建自己的类,并且它还没有从实现了IEnumerable的类继承,那么您可以通过实现IEnumerable(并通过创建其新的GetEnumerator方法将返回的枚举器类)使您的类在foreach语句中可用。
IEnumerable和IEnumerator的区别:
IEnumerable内部使用IEnumerator。 IEnumerable不知道哪个项目/对象正在执行。 无论何时将IEnumerator传递给另一个函数,它都知道项/对象的当前位置。 当我们将IEnumerable集合传递给另一个函数时,它 不知道项目/对象的当前位置(不知道正在执行哪个项目) IEnumerable有一个方法GetEnumerator()
public interface IEnumerable<out T>: IEnumerable { IEnumerator < T > GetEnumerator (); }
IEnumerator有一个名为Current的属性和两个方法,Reset()和MoveNext()(这对于了解列表中项目的当前位置非常有用)。
public interface IEnumerator
{
object Current { get; }
bool MoveNext();
void Reset();
}