<?xml version="1.0" encoding="utf-8" ?><rss version="2.0"><channel><title>DongPad</title><link>http://www.dongpad.com</link> <description>Every day is a new beginning!</description><copyright>2.0 beta 03</copyright> <language>zh-cn</language><item><title>c#的default、using和yield使用小结</title><description><![CDATA[<p>一、default的应用场合</p>  <p>1、switch...case    <br />在switch语句中，如果没有任何case表达式与开关值匹配，则控制传递给跟在可选default标签后的语句。如果没有default标签，则控制传递到switch以外。     <br />对于c#，为了便于维护，建议default项最好要写。     <br />示例代码:</p>  <p><img height="16" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif" width="11" align="top" />Code</p>  <p>2、在泛型类和泛型方法中，在预先未知以下情况时，如何将默认值分配给参数化类型T：    <br />(1)T是引用类型还是值类型;     <br />(2)如果T为值类型，则它是数值还是结构。     <br />示例代码:</p>  <p>public class GenericClass<T>    <br />&#160;&#160;&#160; {     <br />public static T GetDefaultT<T>(T obj)     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; {     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; obj = default(T); //将默认值分配给参数化类型T     <br />return obj;     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; }     <br />&#160;&#160;&#160; }</p>  <p>备注:&#160; 给定参数化类型T的一个变量obj，只有当T为数值类型而且不是结构时，语句t = 0才能正常使用；只有当T为引用类型时，语句obj= null才有效。    <br />使用default关键字，对于数值类型会返回零，对于引用类型会返回空，对于结构，此关键字将返回初始化为零或空的每个结构成员，具体取决于这些结构是值类型还是引用类型。     <br />看下面的代码：</p>  <p><img height="16" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif" width="11" align="top" />Code</p>  <p>二、using的应用场合    <br />1、直接引入命名空间     <br />using System.Data.SqlClient; //引入命名空间     <br />2.using别名。using + 别名 = 包括详细命名空间信息的具体的类型。     <br />这种做法有个好处就是当同一个cs引用了两个不同的命名空间，但两个命名空间都包括了一个相同名字的类型的时候。当需要用到这个类型的时候，就每个地方都要用详细命名空间的办法来区分这些相同名字的类型。而用别名的方法会更简洁，用到哪个类就给哪个类做别名声明就可以了。     <br />注意：并不是说两个名字重复，给其中一个用了别名，另外一个就不需要用别名了，如果两个都要使用，则两个都需要用using来定义别名的。     <br />例如我们用以下语句引入using System.Data.SqlClient命名空间：     <br />using SqlServer=using System.Data.SqlClient;     <br />这时我们就可以用 SqlServer表示using System.Data.SqlClient命名空间，给程序书写带来方便。     <br />3、using语句定义一个范围，在该范围内处理对象。     <br />当年刚学asp.net那会，曾经对照着书本，吭哧吭哧动手写了很多类似下面的代码：</p>  <p><img height="16" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif" width="11" align="top" />Code</p>  <p>直到遇到SqlHelper，才省了很多力气花在业务逻辑上，当年真是...,呵呵。    <br />言归正传，什么时候适合用using呢?当在某个代码段中使用了类的实例，而希望无论因为什么原因，只要离开了这个代码段就自动调用这个类实例的Dispose方法。要达到这样的目的，用try...finally是可以的，但用using看起来更方便和简洁。看下面的代码：</p>  <p><img height="16" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif" width="11" align="top" />Code</p>  <p>我们看到，using确实比try...finally少几行代码，不过，它们的性能怎么样呢？看两个方法各自生成的对应的IL：    <br />（1）使用using     <br /><img alt="" src="http://images.cnblogs.com/cnblogs_com/wjfluisfigo/il1.png" border="0" />     <br />（2）使用try...finally     <br /><img alt="" src="http://images.cnblogs.com/cnblogs_com/wjfluisfigo/il2.png" border="0" />     <br />原来它们的性能几乎是一样的。上面的两段IL可以作为using和try...finally性能的参照。如果你在程序中经常try...catch或者using，对性能的影响是很明显的。     <br />需要引起注意的是，using实例化一个对象的时候，对应的类必须实现IDisposable接口，比如我们延续上面的代码，增加一个如下方法：</p>  <p>static void Test()    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; {     <br />using (Program program = new Program()) //编译器报错，Program类必须要实现IDisposable接口     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {     <br />//do something     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; }</p>  <p>正像注释写的那样，类Program必须实现IDisposable接口，写成class Program : IDisposable{...}这样就可以了。    <br />三、yield的应用     <br />1、<strong>在</strong><strong>迭代器</strong><strong>块中用于向枚举数对象提供值或发出迭代结束信号。      <br /></strong>它的形式如下：     <br />yield return <expression>;或者yield break;     <br />下面看一个示例： </p>  <p><img height="16" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif" width="11" align="top" />     <br />using System;     <br />using System.Collections;     <br />using System.Collections.Generic;     <br />namespace MyCsStudy     <br />{     <br />/// <summary>     <br />/// 程序员,继承接口IEnumerable，实现Programer自己的迭代器     <br />/// </summary>     <br />public class Programer : IEnumerable     <br />&#160;&#160;&#160; {     <br />string[] strNameArr = new string[] { };//存程序员名     <br />public Programer(params string[] inputNames)     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; {     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; strNameArr = new string[inputNames.Length];     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; inputNames.CopyTo(strNameArr, 0);     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; }     <br />public&#160; IEnumerator GetEnumerator()     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; {     <br />foreach (string s in strNameArr)     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {     <br />yield return s; //通过yield return输出遍历程序员名称结果集     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; }     <br />&#160;&#160;&#160; }     <br />class Program     <br />&#160;&#160;&#160; {     <br />static void Main(string[] args)     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; {     <br />string[] programers = new string[] { "jeffery zhao", "dudu", "terrylee", "jeffwong" };     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Programer cnPrograms = new Programer(programers);     <br />//下面注释部分的写法我们非常熟悉     <br />//IEnumerator e = cnPrograms.GetEnumerator();     <br />//while (e.MoveNext())     <br />//{     <br />//&#160;&#160;&#160; Console.WriteLine(e.Current);     <br />//}     <br />//foreach in 和上面的注释代码实质是等价的     <br />foreach (string s in cnPrograms)     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Console.WriteLine(s);     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Console.ReadLine();     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; }     <br />&#160;&#160;&#160; }     <br />}</p>  <p>2、几个要注意的地方&#160; <br />（1）、计算表达式并以枚举数对象值的形式返回；expression 必须可以隐式转换为迭代器的 yield 类型。     <br />（2）、yield 语句只能出现在iterator 块中，该块可用作方法、运算符或访问器的体。     <br />这类方法、运算符或访问器的体受以下约束的控制：     <br />a、不允许不安全块。     <br />b、方法、运算符或访问器的参数不能是 ref 或 out。     <br />c、yield 语句不能出现在匿名方法中。     <br />（3）、当和expression一起使用时，yield return语句不能出现在catch块中或含有一个或多个catch子句的 try 块中。</p>  <p>3、最后，为了深入理解迭代，我们有必要介绍一下.net两个和迭代关联密切的接口：IEnumerable和IEnumerator    <br />（1）、IEnumerable和IEnumerator元数据对比     <br />a、IEnumerator</p>  <p><img height="16" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif" width="11" align="top" />     <br />using System;     <br />using System.Runtime.InteropServices;     <br />namespace System.Collections     <br />{     <br />// 摘要:     <br />//&#160;&#160;&#160;&#160; 支持对非泛型集合的简单迭代。     <br />&#160;&#160;&#160; [ComVisible(true)]     <br />&#160;&#160;&#160; [Guid("496B0ABF-CDEE-11d3-88E8-00902754C43A")]     <br />public interface IEnumerator     <br />&#160;&#160;&#160; {     <br />// 摘要:     <br />//&#160;&#160;&#160;&#160; 获取集合中的当前元素。     <br />//     <br />// 返回结果:     <br />//&#160;&#160;&#160;&#160; 集合中的当前元素。     <br />object Current { get; }     <br />// 摘要:     <br />//&#160;&#160;&#160;&#160; 将枚举数推进到集合的下一个元素。     <br />//     <br />// 返回结果:     <br />//&#160;&#160;&#160;&#160; 如果枚举数成功地推进到下一个元素，则为 true；如果枚举数越过集合的结尾，则为 false。     <br />bool MoveNext();     <br />//     <br />// 摘要:     <br />//&#160;&#160;&#160;&#160; 将枚举数设置为其初始位置，该位置位于集合中第一个元素之前。     <br />void Reset();     <br />&#160;&#160;&#160; }     <br />}</p>  <p>b、IEnumerable</p>  <p><img height="16" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif" width="11" align="top" />     <br />using System.Runtime.InteropServices;     <br />namespace System.Collections     <br />{     <br />// 摘要:     <br />//&#160;&#160;&#160;&#160; 公开枚举数，该枚举数支持在非泛型集合上进行简单迭代。     <br />&#160;&#160;&#160; [ComVisible(true)]     <br />&#160;&#160;&#160; [Guid("496B0ABE-CDEE-11d3-88E8-00902754C43A")]     <br />public interface IEnumerable     <br />&#160;&#160;&#160; {     <br />// 摘要:     <br />//&#160;&#160;&#160;&#160; 返回一个循环访问集合的枚举数。     <br />//     <br />// 返回结果:     <br />//&#160;&#160;&#160;&#160; 可用于循环访问集合的 System.Collections.IEnumerator 对象。     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; [DispId(-4)]     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; IEnumerator GetEnumerator();     <br />&#160;&#160;&#160; }     <br />}</p>  <p>（2）、说明    <br />IEnumerator：提供在普通集合中遍历的接口，有Current，MoveNext()，Reset()，其中Current属性返回的是object类型，另外两个是实例方法；     <br />IEnumerable： 暴露一个IEnumerator，支持在普通集合中的遍历；     <br />IEnumerator<T>：继承自IEnumerator，有Current属性，返回的是T类型；     <br />IEnumerable<T>：继承自IEnumerable，暴露一个IEnumerator<T>，支持在泛型集合中遍历。</p>  <p>（3）总结    <br />a、通过分析（1）中的源码，你也可以从这两个接口的用词选择上，看出其不同：IEnumerable是一个声明式的接口，声明实现该接口的类是“可枚举（enumerable）”的，但并没有说明如何实现iterator；IEnumerator是一个实现式的接口，IEnumerator类就是一个iterator。     <br />b、一个集合要支持foreach方式的遍历，必须实现IEnumerable接口（即必须以某种方式返回IEnumerator对象）；     <br />c、IEnumerator对象具体实现了iterator（通过内部的MoveNext()，Reset()，Current）。     <br />d、IEnumerable和IEnumerator通过IEnumerable的GetEnumerator()方法建立了连接，客户端可以通过IEnumerable的GetEnumerator()得到IEnumerator对象，所以从实质上来讲，将GetEnumerator()看作IEnumerator对象的工厂方法也未尝不可。</p>  <p><a href="http://www.cnblogs.com/wjfluisfigo/archive/2009/06/20/1504377.html">原文参见这里</a></p>]]></description><author>Jack</author><link>http://www.dongpad.com/CSharp-20090628-194.html</link><pubdate>2009-6-28 15:14:45</pubdate></item></channel></rss>