C# 2.0 新特性之迭代器, Yield Return

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

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

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

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

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

None.gif      public   class  C1IterationDemo:IEnumerable,IEnumerator
ExpandedBlockStart.gifContractedBlock.gif    
dot.gif {
ExpandedSubBlockStart.gifContractedSubBlock.gif        
IEnumerable 成员#region IEnumerable 成员
InBlock.gif
InBlock.gif        
public IEnumerator GetEnumerator()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
return this;
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockEnd.gif        
#endregion

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
IEnumerator 成员#region IEnumerator 成员
InBlock.gif
InBlock.gif        
int curIndex=-1;
InBlock.gif        
public void Reset()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            curIndex
=-1;
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
public object Current
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
get
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
if(curIndex < this.allFiles.Count)
ExpandedSubBlockStart.gifContractedSubBlock.gif                
dot.gif{
InBlock.gif                    
return this.allFiles[curIndex];
ExpandedSubBlockEnd.gif                }

InBlock.gif                
throw new Exception("f");
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
public bool MoveNext()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
if(this.allFiles.Count==0)            
InBlock.gif                
return false;
InBlock.gif            curIndex
+=1;
InBlock.gif            
if(curIndex==this.allFiles.Count)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
return false;
ExpandedSubBlockEnd.gif            }

InBlock.gif            
return true;
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockEnd.gif        
#endregion

InBlock.gif
InBlock.gif        
private System.Collections.Specialized.StringCollection allFiles=null;
InBlock.gif        
public  C1IterationDemo GetFiles(string dirPath)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            allFiles
=new System.Collections.Specialized.StringCollection();
InBlock.gif            allFiles.Clear();
InBlock.gif            
foreach(string f in System.IO.Directory.GetFiles(dirPath))
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                allFiles.Add(f);
ExpandedSubBlockEnd.gif            }

InBlock.gif            
return this;    
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedBlockEnd.gif    }

一下是调用:

None.gif             C1IterationDemo c = new  C1IterationDemo().GetFiles( " C:\\WUTemp " );
None.gif            
foreach ( string  s  in  c)
ExpandedBlockStart.gifContractedBlock.gif            
dot.gif {
InBlock.gif                Console.WriteLine(s);
ExpandedBlockEnd.gif            }

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


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


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

None.gif public   class  FileUtility
ExpandedBlockStart.gifContractedBlock.gif    
dot.gif {
InBlock.gif        
public static  IEnumerable<String> GetFiles(string dir)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
foreach(String file in System.IO.Directory.GetFiles(dir))
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                yield 
return file;
ExpandedSubBlockEnd.gif            }

InBlock.gif            
foreach (string dir1 in System.IO.Directory.GetDirectories(dir))
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
foreach(string ff in System.IO.Directory.GetFiles(dir1))
ExpandedSubBlockStart.gifContractedSubBlock.gif                
dot.gif{
InBlock.gif                    yield 
return ff;
ExpandedSubBlockEnd.gif                }

ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

ExpandedBlockEnd.gif    }

None.gif
调用

None.gif          foreach (String f  in  FileUtility.GetFiles( " c:\\wutemp " ))
ExpandedBlockStart.gifContractedBlock.gif            
dot.gif {
InBlock.gif                System.Diagnostics.Debug.WriteLine(f);
ExpandedBlockEnd.gif            }


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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值