一直想写一系列如何提高Performance和Scalability的文章,把我的相关经验和所知道的相关的技巧同大家分享。前一阵在园子里有一篇讨论for each 和 for两种循环那个具有更好的performance的blog,议论得沸沸扬扬。我觉得这是一个很好的切入点,我就已此作为引子,开始我的这个系列的文章。这篇文章的重点不是在于比较这两种循环孰优孰劣,我将讨论的重点是如何更好地定义Collection,如何在判断在什么时候该用Array,什么时候用Collection。
一、for each的本质
我们知道,所有实现了System.Collections. IEnumerable接口的类,我们都可以对它运用for each loop。为了弄清楚它的执行过程,我先给出一个Sample:
using System; using System.Collections.Generic; using System.Text; using System.Collections; namespace Artech.CustomCollection { struct Employee { PrivateFields #region PrivateFields private string _employeeID; private string _name; private int _age; #endregion Constructor #region Constructor public Employee( string employeeID, string name, int age) { this ._employeeID = employeeID; this ._name = name; this ._age = age; } #endregion PublicProperties #region PublicProperties public string EmployeeID { get { return _employeeID;} set {_employeeID = value;} }public string Name { get { return _name;} set {_name = value;} }public int Age { get { return _age;} set {_age = value;} }#endregion Tostring #region Tostring public override string ToString() { return string .Format( " \tID:\t{0}\n\tName:\t{1}\n\tAge:\t{2}\n\t " , this ._employeeID, this ._name, this ._age); } #endregion }class EmployeeList:IEnumerable { private Employee[]_employees; public Employee[]Employees { get { return _employees;} set {_employees = value;} }IEnumerableMembers #region IEnumerableMembers public virtual IEnumeratorGetEnumerator() { Console.WriteLine( " EmployeeList.GetEnumerator()isinvoked " ); return new GenericEmployeeEnumerator( this ._employees); } #endregion }class EmployeeEnumerator:IEnumerator { private Employee[]_employees; private int _index = - 1 ; public EmployeeEnumerator(Employee[]employees) { this ._employees = employees; } IEnumeratorMembers #region IEnumeratorMembers public object Current { get { Console.WriteLine( " EmployeeEnumerator.Currentisinvoked " ); return this ._employees[ this ._index]; } }public bool MoveNext() { Console.WriteLine( " EmployeeEnumerator.MoveNextisinvoked " ); if ( this ._index < this ._employees.Length - 1 ) { this ._index ++ ; return true ; } return false ; } public void Reset() { this ._index = - 1 ; } #endregion }class Program { static void Main( string []args) { Employee[]employees = new Employee[] { new Employee( " 0001 " , " ZhangSan " , 21 ), new Employee( " 0002 " , " LiSi " , 30 )} ; EmployeeListempoyeeList = new EmployeeList(); empoyeeList.Employees = employees; Console.WriteLine( " Beginforeachloop " ); foreach (Employeeemployee in empoyeeList) { Console.WriteLine(employee.ToString()); } Console.WriteLine(" \n\nBeginwhileloop " ); IEnumeratorenumerator = empoyeeList.GetEnumerator(); while (enumerator.MoveNext()) { Employeeemployee = (Employee)enumerator.Current; Console.WriteLine(employee.ToString()); } } } }
我们先运行一下上面的程序再来讲述具体的执行的流程。
在上面的Sample中我们先定义了一个Employee的struct,之所以使用struct而不用一般的class,我将在后面的部分介绍。
struct Employee { PrivateFields #region PrivateFields private string _employeeID; private string _name; private int _age; #endregion Constructor #region Constructor public Employee( string employeeID, string name, int age) { this ._employeeID = employeeID; this ._name = name; this ._age = age; } #endregion PublicProperties #region PublicProperties public string EmployeeID { get { return _employeeID;} set {_employeeID = value;} }public string Name { get { return _name;} set {_name = value;} }public int Age { get { return _age;} set {_age = value;} }#endregion Tostring #region Tostring public override string ToString() { return string .Format( " \tID:\t{0}\n\tName:\t{1}\n\tAge:\t{2}\n\t " , this ._employeeID, this ._name, this ._age); } #endregion }
然后我们基于这个Emplyee struct,定义了与之对应的Collection:EmplyeeList。EmplyeeList实现了System.Collections. IEnumerable接口。并以一个virtual 方法的形式实现了该接口的GetEnumerator方法。(为什么用virtual方法的原因,我会再后续部分解释)。
Public virtual IEnumeratorGetEnumerator()