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 块中,这种块可作为方法、运算符或访问器的主体实现。 这类方法、运算符或访问器的体受以下约束的控制:
-
不允许不安全块。
-
yield return 语句不能放在 try-catch 块中的任何位置。 该语句可放在后跟 finally 块的 try 块中。
-
yield break 语句可放在 try 块或 catch 块中,但不能放在 finally 块中。
重点是,不能放在我们的try catch 语句中滴呀; 我们直接放代码说话。感觉还是挺好的,今天我来加班,我快乐!
public class Info { //你可以这样写 public IEnumerable<Person> personList { get { try { return new List<Person>() { new Person() { Name="jack",Age=12 }, new Person() { Name="jack",Age=13 } }; } catch (Exception ex) { return null; } } } //或者这样写; public IEnumerable<Person> personListByYiled { get { yield return new Person() { Name = "jack", Age = 12 }; yield return new Person() { Name = "jack", Age = 13 }; } } //但是不可以这样写!!!!!!!!!!!!!!!!! public IEnumerable<Person> EorrPersonList { get { try { yield return new Person() { Name = "jack", Age = 12 }; yield return new Person() { Name = "jack", Age = 13 }; } catch (Exception ex) { return null; } } } }
这里,我们又提到了异常捕获,我们也讲究复习一下嘛;
public class FuckLife { //这了我们俩看看try catch finally 中嵌套return的情况; //常规情况; public void Test() { try { } catch(Exception ex) { } finally { //大家知道finally 语句中的语句都会执行的 //那如果 catch 中有了 return,会是怎样的结果呢 } Console.WriteLine("------");//没有return,这里的语句就会被执行; } public int Test1(int a,int b) { try { int result = a / b; return result; } catch (Exception ex) { return 0;//return 阻止了finally后面的代码,但是不会阻止finally 中的代码 } finally { //那如果 catch 中有了 return,会是怎样的结果呢: 答案是会执行的; //return 0; finally 中,是不会有return的滴呀; Console.WriteLine("finally"); } return 100; //就算是这有return,也无法访问; Console.WriteLine("这里的语句,会不会执行呢,答案是不会的会的"); } //总结:当catch 中有了return,finally中的语句还是会执行;但是finally之后的代码无法访问; }
/总结:当catch 中有了return,finally中的语句还是会执行;但是finally之后的代码无法访问;
return 阻止了finally后面的代码,但是不会阻止finally (里面)中的代码。
我们来看看编译后的代码;
我们可以看到,其实在try或者catch中return,相当于在声明了一个变量,把要return的值赋给变量,最后再在finally之后(其实是整个函数运行到最后)才返回这个变量

所以......
public class mssq { public int GetValue(int a ,int b) { int result = 0; //没有必要将我们的return 嵌套在我们的try catch 语句中,直接申明一个结果变量来保存我们想要的值,就可以了 try { result = a / b; } catch(Exception ex) { //异常信息不活,或者其他操作; result = -1; } return result; } }
这里在附加一个基础题的复习;
//结果是1; static int getVal() { int times = 1; return times++; //先进行前面的return 运算 在++ 结果:1 } static int getVal2() { int times = 1; return times = times + 1; //先加,再return 结果:2 } static int getVal3() { int times = 1; return ++times; //先加,再return 结果:2 } //类似的一个经典题; static void getTest() { int i = 0; int j = 0; int iResult = i++; int jResult = ++j; Console.WriteLine(iResult); //0 Console.WriteLine(jResult); //1 }