在学习协同时,看到这篇文章讲解枚举数(Enumerator)和可枚举类型(Enumerable),还不错:
http://www.cnblogs.com/YeYunRong/p/5212201.html。于是就自己在脚本中实验了。并做了自己的修改。
这里并没有定义一个新的可枚举类型类,而是直接将原ColorEnumerator类继承了IEnumerator和IEnumerable接口,并直接在类中实现了GetEnumerator()。这样也能直接使用foreach遍历了。需要注意的是,不管是MoveNext()还是foreach,都会使得枚举数当前位置是最后一个。使用的时候注意需要调用Reset()。
public class IEnumerator_Test : MonoBehaviour
{
// 摘自http://www.cnblogs.com/YeYunRong/p/5212201.html
// C#的枚举数(Enumerator)和可枚举类型(Enumerable)
// 数组可以被foreach语句遍历数组中的元素,原因是数组可以按需提供一个叫做枚举数(enumerator)的对象.枚举数可以依次返回请求的数组的元素.
// 对于有枚举数的类型而言,必须有一个方法来获取它们.在.NET中获取一个对象枚举数的标准用法是调用对象的GetEnumerator方法.实现GetEnumerator方法的类型叫做可枚举类型(enumerable),数组就是可枚举类型.
// 要注意枚举数(enumerator)和可枚举类型(enumerable)的区别和联系.
// 枚举数是可以依次返回集合项的类对象,可枚举类型是带有GetEnumerator方法的类型,它返回枚举数.
// 当foreach被用来遍历可枚举类型时,它就会执行如下的行为:
// 1.通过调用GetEnumerator方法获取对象的枚举数.
// 2.从枚举数中请求每一项并且把它作为迭代变量,代码可以读但不可以改变.
// 枚举数共有3种,可以用以下方式来实现枚举数:
// 1 IEnumerator/IEnumerable接口,叫做非泛型接口形式.
// 2 IEnumerator
/IEnumerable
接口,叫做泛型接口形式.
// 3 不使用接口形式.
// IEnumerator接口
// IEnumerator接口包含3个函数成员:Current,MoveNext,Reset
// Current:返回序列中当前项的属性,它是一个只读属性.返回object类型的引用,所以可以返回任何类型.
// MoveNext:是把枚举数位置前进到集合的下一项的方法,它返回布尔值,指示新位置是有效位置还是已经超过了序列的尾部.如果是已经到达了尾部,则返回false.
// Reset:方法把位置重置为原始状态.
void Start ()
{
//调用枚举数的Current和MoveNext成员函数手工遍历数组中的元素
int[] num = new int[5] {1, 3, 5, 7, 9};
IEnumerator ie = num.GetEnumerator(); //获得枚举数
while (ie.MoveNext()) //移到下一项 (枚举数的初始位置是-1,所以要想获取第一个元素就必须执行MoveNext()方法)
{
Debug.Log(ie.Current);
}
}
}using UnityEngine;
using System.Collections;
using System;
//颜色名数组的枚举数类
class ColorEnumerator : IEnumerator
{
private string[] Colors;
private int Position = -1;
public object Current
{
get
{
if (Position == -1)
{
//如果调用方法失败不是由无效参数造成的,则使用 InvalidOperationException。例如,对于 InvalidOperationException 而言:
//如果创建枚举数后修改了集合中的对象,则由 MoveNext 引发该异常。
//如果执行方法调用前关闭了资源集,则由 GetString 引发该异常。
//如果方法调用失败是由无效参数造成的,则应改为引发 ArgumentException 或其派生类 ArgumentNullException 或 ArgumentOutOfRangeException。
//LdfldaMicrosoft 中间语言 (MSIL)指令引发 InvalidOperationException。
throw new InvalidOperationException(); //InvalidOperationException当方法调用对于对象的当前状态无效时引发的异常。
}
if (Position == Colors.Length)
throw new InvalidOperationException();
return Colors[Position];
}
}
public bool MoveNext()
{
if (Position < Colors.Length - 1)
{
Position++;
return true;
}
else
return false;
}
public void Reset()
{
Position = -1;
}
public ColorEnumerator(string[] theColors) //构造函数
{
Colors = new string[theColors.Length];
for (int i = 0; i < theColors.Length; i++)
Colors[i] = theColors[i];
}
}
public class IEnumerator_Test1 : MonoBehaviour
{
void Start()
{
ColorEnumerator ce = new ColorEnumerator(new string[] { "yellow", "red", "white", "black" });
while (ce.MoveNext())
Debug.Log(ce.Current);
}
}
原本文中说到的
“如果要用foreach来遍历枚举数,需要再定义一个可枚举类型的类,这个类要实现IEnumerable接口的功能.”代码是如下的样子。
//颜色名数组的枚举数类
class ColorEnumerator : IEnumerator,IEnumerable
{
private string[] Colors;
private int Position = -1;
public object Current
{
get
{
if (Position == -1)
throw new InvalidOperationException();
if (Position == Colors.Length)
throw new InvalidOperationException();
return Colors[Position];
}
}
public bool MoveNext()
{
if (Position < Colors.Length - 1)
{
Position++;
return true;
}
else
return false;
}
public void Reset()
{
Position = -1;
}
public IEnumerator GetEnumerator()
{
return this;
}
public ColorEnumerator(string[] theColors) //构造函数
{
Colors = new string[theColors.Length];
for (int i = 0; i < theColors.Length; i++)
Colors[i] = theColors[i];
}
}
//如果要用foreach来遍历枚举数,需要再定义一个可枚举类型的类,这个类要实现IEnumerable接口的功能.
class MyEnumerable : IEnumerable //定义一个可枚举类型的类
{
string[] MyColor = new string[] { "blue", "green", "purple", "pink" };
public IEnumerator GetEnumerator() //实现接口
{
return new ColorEnumerator(MyColor); //返回一个枚举数的对象
}
}
public class IEnumerator_Test1 : MonoBehaviour
{
void Start()
{
MyEnumerable me = new MyEnumerable();
foreach (string i in me)
Debug.Log(i);
}
// Update is called once per frame
void Update()
{
}
}
上面代码中要使用foreach遍历,需要新定义一个可枚举类且实现IEnumerable接口。但是,我将代码改成下面的样子,也能实现。
using UnityEngine;
using System.Collections;
using System;
//颜色名数组的枚举数类
class ColorEnumerator : IEnumerator,IEnumerable
{
private string[] Colors;
private int Position = -1;
public object Current
{
get
{
if (Position == -1)
throw new InvalidOperationException();
if (Position == Colors.Length)
throw new InvalidOperationException();
return Colors[Position];
}
}
public bool MoveNext()
{
if (Position < Colors.Length - 1)
{
Position++;
return true;
}
else
return false;
}
public void Reset()
{
Position = -1;
}
//实现了才能使用foreach遍历
public IEnumerator GetEnumerator()
{
return this;
}
public ColorEnumerator(string[] theColors) //构造函数
{
Colors = new string[theColors.Length];
for (int i = 0; i < theColors.Length; i++)
Colors[i] = theColors[i];
}
}
public class IEnumerator_Test1 : MonoBehaviour
{
void Start()
{
ColorEnumerator ce = new ColorEnumerator(new string[] { "yellow", "red", "white", "black" });
while (ce.MoveNext())
Debug.Log(ce.Current);
ce.Reset(); //如果这里不重置,那么后面的foreach遍历就无效了,因为枚举数当前位置经过上面的while循环后已经是最后一个了位置了。
//同样foreach遍历之后,枚举数的当前位置会是最后一个。
foreach (string i in ce)
Debug.Log(i);
}
// Update is called once per frame
void Update()
{
}
}
如果有大神些发现代码哪有错误或者任何不妥的地方,请指出。