首页 > 代码库 > C#基础复习IEnumerable(和 yield return的使用滴呀 )

C#基础复习IEnumerable(和 yield return的使用滴呀 )

IEnumerable 真是基础中的基础,然而.....

我们直接来看看这个接口的实现吧;

它是一个公开枚举数,该枚举数支持在非泛型集合上进行简单的迭代。换句话说,对于所有数组的遍历,都来自IEnumerable,那么我们就可以利用这个特性,来定义一个能够遍历xxxxxx的通用方法

先看我们的经典实例1:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication4
{

    public class Person:IEnumerable
    {
        public string name;

        public int age;

        public Person(string _name, int _age)
        {
            name = _name;
            age = _age;
        }

        private Person[] per;

        public Person(Person[] arr)
        {
            per=new Person[arr.Length];

            for (int i = 0; i < arr.Length; i++)
            {
                per[i] = arr[i];
            }

        }

        //实现这个接口;
        public IEnumerator GetEnumerator()
        {
            return new PersonEnum(per);
        }

    }

     class PersonEnum : IEnumerator//实现foreach语句内部,并派生
     {

         public Person[] _per; //实现数组;
         int position = -1;
         public PersonEnum(Person[] list)
         {
             _per = list;
         }

         public bool MoveNext()
         {
             position++;
             return (position < _per.Length);
         }

         public void Reset()
         {
             position = -1;
         }
         public object Current   //实现接口的方法;
         {
             get
             {
                 try
                 {
                     return _per[position];
                 }
                 catch (IndexOutOfRangeException)
                 {
                     throw new InvalidOperationException();//抛出异常信息
                 }
             }
         }
     }

    class Program
    {
        
        static void Main(string[] args)
        {
            Person[] per = new Person[2] 

            {
 
                new Person("guojing",21), 

                new Person("muqing",21), 

            };

            //这个。我们就可以进行枚举了;
            Person personlist = new Person(per);

            foreach (Person p in personlist)  //本质上是对数组的枚举,还是通过我们的额index 来实现的滴呀;,只不过要支持foreach的写法,自然要实现我们的ienumberable的重写;
            {
                Console.WriteLine("Name is " + p.name + " and Age is " + p.age);
                //本质上是一种写法的改变滴呀;
            }

            var obj=new Person("muqing", 21);
            foreach (var p in obj)
            {
                //Console.WriteLine("Name is " + p.name + " and Age is " + p.age); bug
            }

            Console.ReadLine();

        }   
    }
}

 

再看我们经典实例二:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication5
{
    public class charlist : IEnumerable
    {
        private string TargetStr { get; set; }

        public charlist(string str)
        {
            this.TargetStr = str;
        }

        public IEnumerator GetEnumerator()
        {
            return new charIterator(TargetStr);
        }


    }

    public class charIterator:IEnumerator
    {
        public string TargetString { get; set; }

        public int position { get; set; }

        public charIterator(string str)
        {
            this.TargetString = str;
            this.position = this.TargetString.Length;
        }

        public object Current
        {
            get
            {
                if (this.position == -1 || this.position == this.TargetString.Length)
                {
                    throw new InvalidOperationException();
                }
                return this.TargetString[this.position];
            }
        }

        public bool MoveNext()
        {
            if (this.position != -1)
            {
                 this.position--;
            }
            return this.position > -1;
        }

        public void Reset()
        {
            this.position = this.TargetString.Length;
        }


    }


    class Program
    {
        static void Main(string[] args)
        {

            //我这里是倒着枚举出来滴哎呦;
            string val = "fuck the life";
            charlist list = new charlist(val);
            foreach (var o in list)
            {
                Console.WriteLine(o);
            }
            Console.ReadLine();


        }
    }
}

 

这里顺便提一下我们的 yield  return 用法的复习和使用滴呀;

上面的两种实现方式可以说是我们net 1.0 的各种常见做法滴呀;

后面,我们将尝试yield return的用法;

 for (int index = this.TargetStr.Length; index > 0;index-- )
      {
        yield return this.TargetStr[index - 1];
      }
 
关于我们的yield return的使用;
 
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication6
{
       
    class Program
    {
        /// <summary>
        /// 获取数据
        /// </summary>
        /// <returns></returns>
        static List<int> GetData()
        {
            return new List<int>() { 1, 2, 3, 4 };
        }

        static IEnumerable<int> WithoutYield()
        {
            List<int> result = new List<int>();
            foreach (var i in GetData())
            {
                if (i > 2)
                {
                     result.Add(i);
                }
            }
            return result;
        }

        static IEnumerable<int> WithYield()
        {
            foreach (var i in GetData())
            {
                if (i > 2)
                {
                    yield return i;
                }
            }
        }

        static void Main(string[] args)
        {

            Console.WriteLine("不使用我们的额yield return的结果;");
            foreach(var val in WithoutYield())
            {
                Console.WriteLine(val);
            }

            Console.WriteLine("使用我们的额yield return的结果;");
            foreach (var val in WithYield())
            {
                Console.WriteLine(val);
            }
            //如果使用我们的f11 调试你会发现,yield 是取出一个就马上返回一个,效果是非常好滴呀;
            //而第一个的做法,是得到所有的结果之后在一次性返回;
            Console.ReadLine();

        }
    }
}

通过调试发现:两种方法的输出结果是一样的,但实际的运作过程是不同的。

第一种方法,是把结果集全部加载到内存中再遍历;

第二种方法,遍历每调用一次,yield return就返回一个值;

因此,当希望获取一个IEnumerable<T>类型的集合,而不想把数据一次性加载到内存,就可以考虑使用yield return的方式去实现;

 

这里还得说说使用它的一个坑滴呀;

yield 语句只能出现在 iterator 块中,这种块可作为方法、运算符或访问器的主体实现。 这类方法、运算符或访问器的体受以下约束的控制:

  • 不允许不安全块。

  • 方法、运算符或访问器的参数不能是 ref 或 out。

  • yield return 语句不能放在 try-catch 块中的任何位置。 该语句可放在后跟 finally 块的 try 块中。

  • yield break 语句可放在 try 块或 catch 块中,但不能放在 finally 块中。

重点是,不能放在我们的try catch 语句中滴呀;

 

C#基础复习IEnumerable(和 yield return的使用滴呀 )