迭代器

来源:互联网 发布:数据库物理模型主键 编辑:程序博客网 时间:2024/04/30 16:47

http://www.cnblogs.com/montaque/archive/2005/04/21/142844.html

C# 2.0 可能讨论比较多的是泛型, 其次可能就是迭代器,匿名方法了. 

这两个特性其实有些本质上的不同, 泛型, 是相对1.1微软在 IL 上面又添加了一些指令来实现. 

而迭代器则是在编译器这个层次去实现的,也就是说C# 2.0 中的迭代器的特性并没有靠引入IL来实现. 

什么是迭代器呢,我拿一个例子来说明. 

比如我们以下一段代码list 一个特定目录下面的所有文件, 代码可能会这么写. 

    public class C1IterationDemo:IEnumerable,IEnumerator 
    
        #region IEnumerable 成员 
 
        public IEnumerator GetEnumerator() 
        
            return this
        }
 
 
        #endregion
 
 
        #region IEnumerator 成员 
 
        int curIndex=-1; 
        public void Reset() 
        
            curIndex=-1; 
        }
 
 
        public object Current 
        
            get 
            
                if(curIndex < this.allFiles.Count) 
                
                    return this.allFiles[curIndex]; 
                }
 
                throw new Exception("f"); 
            }
 
        }
 
 
        public bool MoveNext() 
        
            if(this.allFiles.Count==0)             
                return false
            curIndex+=1; 
            if(curIndex==this.allFiles.Count) 
            
                return false
            }
 
            return true
        }
 
 
        #endregion
 
 
        private System.Collections.Specialized.StringCollection allFiles=null
        public  C1IterationDemo GetFiles(string dirPath) 
        
            allFiles=new System.Collections.Specialized.StringCollection(); 
            allFiles.Clear(); 
            foreach(string f in System.IO.Directory.GetFiles(dirPath)) 
            
                allFiles.Add(f); 
            }
 
            return this;     
        }
 
 
    }

以下是调用: 

            C1IterationDemo c=new C1IterationDemo().GetFiles("C:\\WUTemp"); 
            foreach(string s in c) 
            
                Console.WriteLine(s); 
            }

其中这里foreach 就是调用了IEnumerator的movenext, 类似 foreach 这样的调用方式,一般就是一个迭代器. 


如果要你去实现类似的代码的话,可能也大通小异, 另外,我们枚举文件的时候还没有考虑子目录的情况. 


类似的代码我们用C# 2.0 的话就变得很简单很简单,我一并考虑了子目录的情况. 

public class FileUtility 
    
        public static  IEnumerable<String> GetFiles(string dir) 
        
            foreach(String file in System.IO.Directory.GetFiles(dir)) 
            
                yield return file; 
            }
 
            foreach (string dir1 in System.IO.Directory.GetDirectories(dir)) 
            
                foreach(string ff in FileUtility.GetFiles(dir1)) 
                
                    yield return ff; 
                }
 
            }
 
        }
 
    }
 
调用 

        foreach(String f in FileUtility.GetFiles("c:\\wutemp")) 
            
                System.Diagnostics.Debug.WriteLine(f); 
            }


对比一下代码,后面的代码可能有几个特点: 

1。代码很简洁。其实这里多了一个yield return 语句,由于yield return 并不对应多余的il指令。所以编译器就会在编译的时候,生成一个实现Ienumator接口的类.并且自动维护该类的状态.比如movenext, 

2. 使用yield return 很容易实现递归调用中的迭代器. 如果以上的问题,不使用yield return的话,可想而知.要么你先把所有的结果暂时放到一个对象集合中. 可是这样就以为着在迭代之前一定要计算号. 要么可能你的movenext 就相当的复杂了. .NET 编译生成的代码其实利用了state machine. 代码量也很大. 

类似迭代的调用,比如二叉树遍历 用yield return 就很方便了.另外还有常说的pipeline模式也很方便了. 

可是yield return 还是有一些缺陷. 

比如如果GetFiles 有一个参数是ref 或者 out, 那这个state machine就很难去维护状态了. 事实上,yield return那是不支持方法带有ref或者out参数的情况. 

 

more information,please refer:

Iterations with c2: 
http://www.theserverside.net/articles/showarticle.tss?id=IteratorsWithC2

使用匿名方法、迭代程序和局部类来创建优雅的代码: 
http://www.microsoft.com/china/msdn/library/langtool/vcsharp/CreElegCodAnymMeth.mspx

原创粉丝点击