什么时候应该创建派生自 IEnumerator/IEnumerable 的 类?
When should you create classes that are derived from IEnumerator/IEnumerable?
我确实了解这两个接口(IEnumerator
和 IEnumerable
)的工作原理以及它们的用途。但是,我一直不太明白何时创建从这两个接口之一派生的 class 。据我所知,您可以在列表、数组和其他通用集合上执行 foreach
循环,而不必像我在代码中所做的那样创建 class:
class Program
{
public static int[] array = new int[3] { 1, 2, 3 };
static void Main(string[] args)
{
var Enumerable = new Aninfiniteenumerator();
foreach(var i in infiniteEnumerable)
{
Console.WriteLine($"I is {i}");
}
Console.ReadKey();
}
}
class Aninfiniteenumerator : IEnumerable<int> //Creating a class that is derived from IEnumerable
{
public IEnumerator GetEnumerator()
{
return new MyInfiniteEnumer(Program.array);
}
IEnumerator<int> IEnumerable<int>.GetEnumerator()
{
return new MyInfiniteEnumer(Program.array);
}
}
public class MyInfiniteEnumer : IEnumerator<int> ////Creating a class that is derived from IEnumerator
{
private int[] values;
private int index = -1;
public int Current => values[index];
object IEnumerator.Current => Current;
public MyInfiniteEnumer (int [] values)
{
this.values = values;
}
public void Dispose()
{
}
public bool MoveNext()
{
index++;
return index < values.Length;
}
public void Reset()
{
}
}
PS。我知道我的枚举数被称为“无限枚举数”,但它们并不是无限的。因此,正如我所说,可以在通用 list/an 数组上执行 foreach
循环,而不必创建 IEnumerable
/IEnumerator
classes :
class Program
{
static void Main(string[] args)
{
Random rand = new Random();
List<Car> vehicles = new List<Car>();
for(int i = 0; i < 100; i++)
{
vehicles.Add(new Car(rand.Next(1970,2021), "Honda"));
}
foreach(var car in vehicles)
{
Console.WriteLine(car.yearProduced + ", " + car.model);
}
Console.ReadKey();
for (int i = 0; i < 100; i++)
{
vehicles.Add(new Car(rand.Next(1970, 2021), "Subaru"));
}
foreach (var car in vehicles)
{
Console.WriteLine(car.yearProduced + ", " + car.model);
}
Console.WriteLine(vehicles.Count());
Console.ReadKey();
}
}
class Car
{
public string model { get; set; }
public int yearProduced { get; set; }
public Car (int year, string model)
{
yearProduced = year;
this.model = model;
}
}
回到我的问题,我编写了第一个代码,以便能够在名为“Enumerable”的 var
上执行 foreach
循环。我只是为了练习而编写这段代码,并没有看到创建从 IEnumerable 和 IEnumerator 派生的 classes 的实际用途。所以,我的问题是,在哪些情况下您必须创建从这两个接口之一派生的 class?
可以使用枚举器的自定义结构的一个很好的例子是 二叉树。
最简单的树是
public class Tree
{
public Tree Left { get; set; }
public Tree Right { get; set; }
public object Value { get; set; }
}
这个定义可以用来组合任意树:
var root = new Tree()
{
Left = new Tree() { Value = 1 },
Right = new Tree() { Value = 2 },
Value = 3
}
请注意,我的树是平衡的,但实际的树不一定是。
现在,您应该如何枚举所有值?这不是那么容易,在每个节点中你必须决定它是否有子节点,当你在节点上完成后,你必须回到它的父节点并探索所有路径。
但是客户端代码对难不难不感兴趣,它期望代码是
foreach ( var val in root )
{
// I want all values from the tree here!
}
此时枚举的概念开始变得有意义了。它不仅仅是关于简单的线性结构,如数组或列表!
public class Tree : IEnumerable
{
public IEnumerator GetEnumerator()
{
if ( Left != null ) foreach ( var e in Left ) yield return e;
if ( Right != null ) foreach ( var e in Right ) yield return e;
yield return Value;
}
}
我希望这个例子能对这个问题有所启发。
我确实了解这两个接口(IEnumerator
和 IEnumerable
)的工作原理以及它们的用途。但是,我一直不太明白何时创建从这两个接口之一派生的 class 。据我所知,您可以在列表、数组和其他通用集合上执行 foreach
循环,而不必像我在代码中所做的那样创建 class:
class Program
{
public static int[] array = new int[3] { 1, 2, 3 };
static void Main(string[] args)
{
var Enumerable = new Aninfiniteenumerator();
foreach(var i in infiniteEnumerable)
{
Console.WriteLine($"I is {i}");
}
Console.ReadKey();
}
}
class Aninfiniteenumerator : IEnumerable<int> //Creating a class that is derived from IEnumerable
{
public IEnumerator GetEnumerator()
{
return new MyInfiniteEnumer(Program.array);
}
IEnumerator<int> IEnumerable<int>.GetEnumerator()
{
return new MyInfiniteEnumer(Program.array);
}
}
public class MyInfiniteEnumer : IEnumerator<int> ////Creating a class that is derived from IEnumerator
{
private int[] values;
private int index = -1;
public int Current => values[index];
object IEnumerator.Current => Current;
public MyInfiniteEnumer (int [] values)
{
this.values = values;
}
public void Dispose()
{
}
public bool MoveNext()
{
index++;
return index < values.Length;
}
public void Reset()
{
}
}
PS。我知道我的枚举数被称为“无限枚举数”,但它们并不是无限的。因此,正如我所说,可以在通用 list/an 数组上执行 foreach
循环,而不必创建 IEnumerable
/IEnumerator
classes :
class Program
{
static void Main(string[] args)
{
Random rand = new Random();
List<Car> vehicles = new List<Car>();
for(int i = 0; i < 100; i++)
{
vehicles.Add(new Car(rand.Next(1970,2021), "Honda"));
}
foreach(var car in vehicles)
{
Console.WriteLine(car.yearProduced + ", " + car.model);
}
Console.ReadKey();
for (int i = 0; i < 100; i++)
{
vehicles.Add(new Car(rand.Next(1970, 2021), "Subaru"));
}
foreach (var car in vehicles)
{
Console.WriteLine(car.yearProduced + ", " + car.model);
}
Console.WriteLine(vehicles.Count());
Console.ReadKey();
}
}
class Car
{
public string model { get; set; }
public int yearProduced { get; set; }
public Car (int year, string model)
{
yearProduced = year;
this.model = model;
}
}
回到我的问题,我编写了第一个代码,以便能够在名为“Enumerable”的 var
上执行 foreach
循环。我只是为了练习而编写这段代码,并没有看到创建从 IEnumerable 和 IEnumerator 派生的 classes 的实际用途。所以,我的问题是,在哪些情况下您必须创建从这两个接口之一派生的 class?
可以使用枚举器的自定义结构的一个很好的例子是 二叉树。
最简单的树是
public class Tree
{
public Tree Left { get; set; }
public Tree Right { get; set; }
public object Value { get; set; }
}
这个定义可以用来组合任意树:
var root = new Tree()
{
Left = new Tree() { Value = 1 },
Right = new Tree() { Value = 2 },
Value = 3
}
请注意,我的树是平衡的,但实际的树不一定是。
现在,您应该如何枚举所有值?这不是那么容易,在每个节点中你必须决定它是否有子节点,当你在节点上完成后,你必须回到它的父节点并探索所有路径。
但是客户端代码对难不难不感兴趣,它期望代码是
foreach ( var val in root )
{
// I want all values from the tree here!
}
此时枚举的概念开始变得有意义了。它不仅仅是关于简单的线性结构,如数组或列表!
public class Tree : IEnumerable
{
public IEnumerator GetEnumerator()
{
if ( Left != null ) foreach ( var e in Left ) yield return e;
if ( Right != null ) foreach ( var e in Right ) yield return e;
yield return Value;
}
}
我希望这个例子能对这个问题有所启发。