文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>.NET学习之Foreach……

.NET学习之Foreach……

时间:2010-09-14  来源:英雄不问出处

 

 对于.NET Framework提供的“标准”的集合类型可以直接使用foreach,如(Array、ArrayList、HashTable),除此之外,对于自定义的集合对象,也可以使其支持foreach的使用,只要实现IEnumerable接口即可(刚提到的几种集合类型都实现了这个接口)。

例一 public class HelloCollection : IEnumerable
    {
        public IEnumerator GetEnumerator ()
        {
            yield return "Hello";
            yield return "World";
        }
}
  class CustomerForeach
    {
        static void Main()
        {
            HelloCollection helloCollection = new HelloCollection();
            foreach (string s in helloCollection)
            {
                Console.WriteLine(s + "……");
            }
            Console.ReadKey();
        }
    }

 运行可以看到正确的输出了“Hello……  World……”,问题的关键就在 “IEnumerator”的 “IEnumerable.GetEnumerator()”这个方法,以及yield关键字,单步运行程序会发现程序运行至foreach语句之后跳转至HelloCollection中的GetEnumerator方法,然后遇到“yield  return”就返回,接着执行下一个,直到返回所有的yield……

修改上述代码,比方说改为如下代码,先猜测下结果,然后运行看输出什么。 

例二 public class HelloCollection : IEnumerable
    {
        public IEnumerator GetEnumerator()
        {
            Console.WriteLine("跳转至GetEnumerator方法");
            Console.WriteLine("即将输出");
            yield return "Hello";
            Console.WriteLine("下一个输出");
            yield return "World";
        }
    }
class CustomerForeach
    {
        static void Main()
        {
            HelloCollection helloCollection = new HelloCollection();
            foreach (string s in helloCollection)
            {
                Console.WriteLine("foreach方法");
                Console.WriteLine(s );
            }
            Console.ReadKey();
        }
    }

结果输出的是

跳转至GetEnumerator方法
即将输出:
foreach方法
Hello
下一个输出:
foreach方法
World

   看明白了?遇到一个yield return 就返回到foreach,而且在foreach内部使用的s就是返回的值……

 

再看个代码 

例三 class CustomerForeach
    {
        static void Main()
        {
            Peoples ps = new Peoples();
            foreach (People p in ps)
            {
                Console.WriteLine(p);
            }
            Console.ReadKey();
        }
    }

    class People
    {
        public string Name;
        public int Age;
        //重写基类object的Tostring方法()以按一下格式提供有意义的信息
        //姓名:年龄
        public override string ToString()
        {
            //return base.ToString();
            return Name + ":" + Age.ToString();
        }
    }
    class Peoples:IEnumerable
    {
        private People[] objects;
        private Random ran = new Random();
        private void FillElements()
        {
            objects = new People[10];
            for (int i = 0; i < 10; i++)
            {
                objects[i] = new People();
                objects[i].Name = "People" + (i+1).ToString();
                objects[i].Age = ran.Next(1,100);
            }
        }

        public Peoples()
        {
            FillElements();
        }

        #region IEnumerable 成员

        IEnumerator IEnumerable.GetEnumerator()
        {        
           // throw new NotImplementedException();
            foreach (People people in objects)
            {
                 yield return people;
            }  
        }

        #endregion
    }

 

这个自己测试吧,通过查找可以知道IEnumerable里就一个方法是IEnumerator GetEnumerator();而IEnumerator接口原型如下(查询VS2008文档得知) 

public interface IEnumerator
{
//获取集合中的当前元素。
  object Current { get; }
//将枚举数推进到集合的下一个元素。
bool MoveNext();
//将枚举数设置为其初始位置,该位置位于集合中第一个元素之前。
void Reset();
}

  以下是自带的解释

解释 C# 语言的 foreach 语句(在 Visual Basic 中为 For Each)隐藏了枚举数的复杂性。因此,建议使用 foreach,而不直接操作枚举数。

枚举数可用于读取集合中的数据,但不能用于修改基础集合。

最初,枚举数定位在集合中第一个元素前。Reset 方法还会将枚举数返回到此位置。在此位置上,Current 属性未定义。因此,在读取 Current 的值之前,必须调用 MoveNext 方法将枚举数提前到集合的第一个元素。

在调用 MoveNext 或 Reset 之前,Current 返回同一对象。MoveNext 将 Current 设置为下一个元素。

如果 MoveNext 越过集合的末尾,则枚举数将被放置在此集合中最后一个元素的后面,而且 MoveNext 返回 false。当枚举数位于此位置时,对 MoveNext 的后续调用也返回 false。如果上一个 MoveNext 调用返回 false,则 Current 未定义。若要再次将 Current 设置为集合的第一个元素,可以调用 Reset,然后再调用 MoveNext。

只要集合保持不变,枚举数就保持有效。如果对集合进行更改(如添加、修改或删除元素),则枚举数将失效且不可恢复,而且其行为是不确定的。

枚举数没有对集合的独占访问权;因此,枚举通过集合在本质上不是一个线程安全的过程。若要确保枚举过程中的线程安全,可以在整个枚举过程中锁定集合。若要允许多个线程访问集合以进行读写操作,则必须实现自己的同步。

  最后在加个例子,跟上述相关的

例五:(IEnumerator) class CustomerForeach
    {
        static void Main()
        {           
            int[] values = new int[10]{0,1,2,3,4,5,6,7,8,9};
            ArrayList arrl = new ArrayList();
            arrl.Add("Arr1");
            arrl.Add("Arr3");
            arrl.Add("Arr5");
            Hashtable hst = new Hashtable();
            hst.Add(2, "hst2");
            hst.Add(4, "hst4");
            hst.Add(6, "hst6");
            PrintCollection(values);
            PrintCollection(arrl);
            PrintCollection(hst);
            Console.ReadKey();
        }

        static void PrintCollection(IEnumerable obj)
        {
            //获取迭代访问器
            IEnumerator itor = obj.GetEnumerator();
            //只要集合中还有为访问的元素。movenext方法返回True
            while (itor.MoveNext())
            {
                //itor.Current返回当前的对象
                //本例仅简单的输出其Tostring()方法的结果
                Console.WriteLine(itor.Current.ToString());
            }
        }
    }

 看明白了吗?

相关阅读 更多 +
排行榜 更多 +
辰域智控app

辰域智控app

系统工具 下载
网医联盟app

网医联盟app

运动健身 下载
汇丰汇选App

汇丰汇选App

金融理财 下载