最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C#特性-迭代器(上)及一些研究過程中的副產(chǎn)品

 更新時(shí)間:2014年12月25日 15:03:54   投稿:mdxy-dxy  
這篇文章主要介紹了C#特性-迭代器(上)及一些研究過程中的副產(chǎn)品,需要的朋友可以參考下

提到迭代器我們不能不想到迭代器模式,那我就以迭代器模式作為開場白.

在我們的應(yīng)用程序中常常有這樣一些數(shù)據(jù)結(jié)構(gòu):

它們是一個(gè)數(shù)據(jù)的集合,如果你知道它們內(nèi)部的實(shí)現(xiàn)結(jié)構(gòu)就可以去訪問它們,它們各自的內(nèi)部存儲(chǔ)結(jié)構(gòu)互不相同,各種集合有各自的應(yīng)用場合.說到這里大家可能想出一大堆這樣的集合了:List,Hashtable,ArrayList等等。這些集合各自都有各自的個(gè)性,這就是它們存在的理由。但如果你想遍歷它你必須知道它內(nèi)部的存儲(chǔ)細(xì)節(jié),作為一個(gè)集合元素,把內(nèi)部細(xì)節(jié)暴露出來肯定就不好了,這樣客戶程序就不夠穩(wěn)定了,在你更換集合對象的時(shí)候,比如List不能滿足需求的時(shí)候,你換成Hashtable,因?yàn)橐郧暗目蛻舫绦蜻^多的關(guān)注了List內(nèi)部實(shí)現(xiàn)的細(xì)節(jié),所以不能很好的移植。而迭代器模式就是為解決這個(gè)問題而生的:

提供一種一致的方式訪問集合對象中的元素,而無需暴露集合對象的內(nèi)部表示。
比如現(xiàn)在有這樣一個(gè)需求,遍歷集合內(nèi)的元素,然后輸出,但是并不限定集合是什么類型的集合,也就是未來集合可能發(fā)生改變。

思考:

集合會(huì)發(fā)生改變,這是變化點(diǎn),集合改變了,遍歷方法也改變,我們要保證遍歷的方法穩(wěn)定,那么就要屏蔽掉細(xì)節(jié)。找到了變化點(diǎn)那我們就將其隔離起來(一般使用interface作為隔離手段):假設(shè)所有的集合都繼承自ICollection接口,這個(gè)接口用來隔離具體集合的,將集合屏蔽在接口后面,作為遍歷我們肯定需要這樣一些方法:MoveNext,Current,既然ICollection負(fù)責(zé)數(shù)據(jù)存儲(chǔ),職責(zé)又要單一,那么就新建立一個(gè)接口叫做Iterator吧,每種具體的集合都有自己相對應(yīng)的Iterator實(shí)現(xiàn):

下面是一個(gè)簡易的實(shí)現(xiàn)代碼:

/// <summary>
/// 集合的接口
/// </summary>
  public interface ICollection
  {
    int Count { get; }
    /// <summary>
    /// 獲取迭代器
    /// </summary>
    /// <returns>迭代器</returns>
    Iterator GetIterator();
  }
  /// <summary>
  /// 迭代器接口
  /// </summary>
  public interface Iterator
  {
    bool MoveNext();

    object Current { get; }
  }

  public class List : ICollection
  {
    private const int MAX = 10;
    private object[] items;
    public List()
    { 
      items = new object[MAX];
    }
    public object this[int i]
    {
      get { return items[i]; }
      set { this.items[i] = value; }
    }
    #region ICollection Members

    public int Count
    {
      get { return items.Length; }
    }

    public Iterator GetIterator()
    {
      return new ListIterator(this);
    }

    #endregion
  }
  public class ListIterator : Iterator
  {
    private int index = 0;
    private ICollection list;
    public ListIterator(ICollection list)
    {
      this.list = list;
      index = 0;
    }
    #region Iterator Members

    public bool MoveNext()
    {
      if (index + 1 > list.Count)
        return false;
      else
      { 
        index++;
        return true;
      }
    }

    public object Current
    {
      get { return list[index]; }
    }

    #endregion
  }
  /// <summary>
  /// 測試
  /// </summary>
  public class Program
  {
    static void Main()
    {
      ICollection list = new List();
      Iterator iterator = list.GetIterator();
      while (iterator.MoveNext())
      {
        object current = iterator.Current;
      }
    }
}

看看最后的測試,是不是不管具體的集合如何改變,遍歷代碼都非常穩(wěn)定?而且擴(kuò)展新的集合類也非常方便,只是添加代碼不會(huì)修改原來的代碼,符合開閉原則。當(dāng)然,這么好的解決方案微軟當(dāng)然不會(huì)放過,現(xiàn)在C# 2.0里已經(jīng)內(nèi)置了對迭代器的支持,看看System.Collections, System.Collections.Generic命名空間,所有的集合都實(shí)現(xiàn)了這個(gè)接口:IEnumerable,這個(gè)接口還有泛型的版本。注意到這個(gè)接口只有一個(gè)方法:IEnumerator GetEnumerator();,IEnumerator就是迭代器的接口,相當(dāng)于我的實(shí)例里面的Iterator,它也有泛型的版本。
那么現(xiàn)在在.net里所有的集合類都可以這樣訪問了:

復(fù)制代碼 代碼如下:

IEnumerator ienumerator = list.GetEnumerator();
while(ienumerator.MoveNext())
{
    object current = ienumerator.Current;
}

但是這樣訪問也太麻煩了,所以C#里出現(xiàn)了foreach關(guān)鍵字,我們來看看foreach背后發(fā)生了什么?假如有如下的代碼:

public static void Main()
{      
      ArrayList list = new ArrayList();
      list.Add(1);
      list.Add(2);
      list.Add(3);
      foreach (object item in list)
      {
        Console.WriteLine(item.ToString());
      }
}

下面是它對應(yīng)的IL代碼:

.method private hidebysig static void Main() cil managed
{
  .entrypoint
  .maxstack 2
  .locals init (
    [0] class [mscorlib]System.Collections.ArrayList list,
    [1] object item,
    [2] class [mscorlib]System.Collections.IEnumerator CS$5$0000,
    [3] class [mscorlib]System.IDisposable CS$0$0001)
  L_0000: newobj instance void [mscorlib]System.Collections.ArrayList::.ctor()
  L_0005: stloc.0 
  L_0006: ldloc.0 
  L_0007: ldc.i4.1 
  L_0008: box int32
  L_000d: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object)
  L_0012: pop 
  L_0013: ldloc.0 
  L_0014: ldc.i4.2 
  L_0015: box int32
  L_001a: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object)
  L_001f: pop 
  L_0020: ldloc.0 
  L_0021: ldc.i4.3 
  L_0022: box int32
  L_0027: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object)
  L_002c: pop 
  L_002d: ldloc.0 
  L_002e: callvirt instance class [mscorlib]System.Collections.IEnumerator [mscorlib]System.Collections.ArrayList::GetEnumerator()
  L_0033: stloc.2 
  L_0034: br.s L_0048
  L_0036: ldloc.2 
  L_0037: callvirt instance object [mscorlib]System.Collections.IEnumerator::get_Current()
  L_003c: stloc.1 
  L_003d: ldloc.1 
  L_003e: callvirt instance string [mscorlib]System.Object::ToString()
  L_0043: call void [mscorlib]System.Console::WriteLine(string)
  L_0048: ldloc.2 
  L_0049: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
  L_004e: brtrue.s L_0036
  L_0050: leave.s L_0063
  L_0052: ldloc.2 
  L_0053: isinst [mscorlib]System.IDisposable
  L_0058: stloc.3 
  L_0059: ldloc.3 
  L_005a: brfalse.s L_0062
  L_005c: ldloc.3 
  L_005d: callvirt instance void [mscorlib]System.IDisposable::Dispose()
  L_0062: endfinally 
  L_0063: call string [mscorlib]System.Console::ReadLine()
  L_0068: pop 
  L_0069: ret 
  .try L_0034 to L_0052 finally handler L_0052 to L_0063
}

從.locals init 那里可以看出編譯器為我們添加了兩個(gè)局部變量,一個(gè)就是迭代器。

復(fù)制代碼 代碼如下:

L_002d: ldloc.0
L_002e: callvirt instance class [mscorlib]System.Collections.IEnumerator [mscorlib]System.Collections.ArrayList::GetEnumerator()
L_0033: stloc.2

這三行代碼告訴我們,調(diào)用list的GetEnumerator()方法,獲取迭代器實(shí)例將其賦值給編譯器為我們添加的那個(gè)迭代器局部變量,接著是L_0034: br.s L_0048,
br.s這個(gè)指令是強(qiáng)制跳轉(zhuǎn),我們接著看

復(fù)制代碼 代碼如下:

L_0048: ldloc.2
L_0049: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()

調(diào)用迭代器的MoveNext()方法,L_004e: brtrue.s L_0036 如果是true的話跳轉(zhuǎn),

復(fù)制代碼 代碼如下:

L_0036: ldloc.2
L_0037: callvirt instance object [mscorlib]System.Collections.IEnumerator::get_Current()
L_003c: stloc.1
L_003d: ldloc.1
L_003e: callvirt instance string [mscorlib]System.Object::ToString()
L_0043: call void [mscorlib]System.Console::WriteLine(string)

獲取當(dāng)前值,然后輸出
 看到?jīng)]有,實(shí)際foreach后面干的事就是獲取迭代器,然后一個(gè)while循環(huán),不過這樣一些確實(shí)簡潔多了。
說到這里是不是

復(fù)制代碼 代碼如下:

IEnumerator ienumerator = list.GetEnumerator();
            while (ienumerator.MoveNext())
            {
                object item = ienumerator.Current;
                Console.WriteLine(item.ToString());
            }

復(fù)制代碼 代碼如下:

 foreach (object item in list)
            {
                Console.WriteLine(item.ToString());
            }

這兩樣代碼是一樣的呢?如果不一樣那推薦使用哪一個(gè)呢?當(dāng)然是使用第二種,簡潔嘛,除了簡潔之外就沒有其它的了?細(xì)心讀者會(huì)發(fā)現(xiàn)上面的IL代碼,
在結(jié)束循環(huán)后還有一大塊,可我們的C#代碼中并沒有啊,接著分析:
.try L_0034 to L_0052 finally handler L_0052 to L_0063
這里說明從L_0034到L_0052是被放在try里面的,恰好這段代碼是循環(huán)體里的東西,L_0052到L_0063里是放在finally里的,看來foreach還給我們加了一
個(gè)try{}finally{}結(jié)構(gòu)啊。那看看L_0052到L_0063里是什么東西吧:

復(fù)制代碼 代碼如下:

L_0052: ldloc.2
    L_0053: isinst [mscorlib]System.IDisposable
    L_0058: stloc.3
    L_0059: ldloc.3
    L_005a: brfalse.s L_0062
    L_005c: ldloc.3
    L_005d: callvirt instance void [mscorlib]System.IDisposable::Dispose()
    L_0062: endfinally
    L_0063: call string [mscorlib]System.Console::ReadLine()

判斷迭代器對象是否是一個(gè)IDisposable實(shí)例,如果是,那就要調(diào)用它的Dispose()方法了(為啥它要實(shí)現(xiàn)IDisposable接口?那肯定這個(gè)迭代器里使用了一些非托管資源)。
看到了吧,foreach也真夠智能的,看來使用foreach的方式是比自己用while方式安全穩(wěn)定多了。

(PS:好像是扯遠(yuǎn)了點(diǎn),不過大家一起了解一下,呵呵,其實(shí)我當(dāng)初也沒想說這個(gè),不過后來看IL代碼有點(diǎn)不對勁,就當(dāng)作個(gè)副產(chǎn)品吧)

C# 2.0里還出現(xiàn)個(gè)關(guān)鍵字yield,我看了半天MSDN也沒明白它的意思:

在迭代器塊中用于向枚舉數(shù)對象提供值或發(fā)出迭代結(jié)束信號(hào)。到現(xiàn)在還是沒明白,不過yield這個(gè)東西后面卻包含了很多東西,有一些非?!捌婀帧钡奶匦裕?br /> 我稱之為奇怪的意思是與我們以前的思維有的不符,Linq的一些特質(zhì)也是建立在這個(gè)特性之上的。關(guān)于yield的更多討論我想放在另外一篇文章中,因?yàn)槲矣X得有必要。

相關(guān)文章

  • 人臉認(rèn)證源碼faceIdentify詳解

    人臉認(rèn)證源碼faceIdentify詳解

    這篇文章主要為大家詳細(xì)介紹了人臉認(rèn)證源碼faceIdentify的相關(guān)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-08-08
  • c#實(shí)現(xiàn)sunday算法實(shí)例

    c#實(shí)現(xiàn)sunday算法實(shí)例

    Sunday算法思想跟BM算法很相似,在匹配失敗時(shí)關(guān)注的是文本串中參加匹配的最末位字符的下一位字符,下面是用C#實(shí)現(xiàn)sunday的實(shí)例代碼,有需要的朋友可以參考一下
    2013-08-08
  • C#中多維數(shù)組[,]和交錯(cuò)數(shù)組[][]的區(qū)別

    C#中多維數(shù)組[,]和交錯(cuò)數(shù)組[][]的區(qū)別

    這篇文章介紹了C#中多維數(shù)組[,]和交錯(cuò)數(shù)組[][]的區(qū)別,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-01-01
  • C#讀取csv格式文件的方法

    C#讀取csv格式文件的方法

    這篇文章主要介紹了C#讀取csv格式文件的方法,包括針對csv文件操作的規(guī)則,實(shí)例代碼部分包含了數(shù)據(jù)有效性驗(yàn)證及行列驗(yàn)證等內(nèi)容,邏輯嚴(yán)謹(jǐn),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2014-10-10
  • C#后臺(tái)創(chuàng)建控件并獲取值的方法

    C#后臺(tái)創(chuàng)建控件并獲取值的方法

    這篇文章主要介紹了C#后臺(tái)創(chuàng)建控件并獲取值的方法,實(shí)例講述了前臺(tái)與后臺(tái)的具體實(shí)現(xiàn)方法,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-01-01
  • Unity實(shí)現(xiàn)UI漸隱漸顯效果

    Unity實(shí)現(xiàn)UI漸隱漸顯效果

    這篇文章主要為大家詳細(xì)介紹了Unity實(shí)現(xiàn)UI漸隱漸顯效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-04-04
  • C#實(shí)現(xiàn)圖片邊緣銳化的完整代碼

    C#實(shí)現(xiàn)圖片邊緣銳化的完整代碼

    在 C# 中進(jìn)行圖像的邊緣銳化,可以通過卷積濾波器實(shí)現(xiàn),邊緣銳化的基本思想是通過卷積核(也稱為濾波器或掩模)來增強(qiáng)圖像中的邊緣,下面是如何在 C# 中實(shí)現(xiàn)這一操作的完整代碼,需要的朋友可以參考下
    2024-06-06
  • winform把Office轉(zhuǎn)成PDF文件

    winform把Office轉(zhuǎn)成PDF文件

    這篇文章介紹了winform把Office轉(zhuǎn)成PDF文件的方法,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-06-06
  • WPF使用HLSL實(shí)現(xiàn)百葉窗動(dòng)畫效果

    WPF使用HLSL實(shí)現(xiàn)百葉窗動(dòng)畫效果

    百葉窗動(dòng)畫是制作PPT時(shí)常用的動(dòng)畫之一,本文將通過實(shí)現(xiàn)百葉窗動(dòng)畫效果的例子介紹在WPF中如何使用ShaderEffect,感興趣的小伙伴可以了解一下
    2023-09-09
  • C#調(diào)用Oracle存儲(chǔ)過程的方法

    C#調(diào)用Oracle存儲(chǔ)過程的方法

    這篇文章主要介紹了C#調(diào)用Oracle存儲(chǔ)過程的方法,包含數(shù)據(jù)庫及C#對應(yīng)的調(diào)用代碼,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-01-01

最新評(píng)論

拉萨市| 诸暨市| 隆昌县| 黄梅县| 衡东县| 彰化县| 绥江县| 宝丰县| 拜城县| 天峻县| 济源市| 新乡市| 石台县| 大余县| 淄博市| 萨迦县| 宝兴县| 莆田市| 莆田市| 高雄市| 扶风县| 乳山市| 达拉特旗| 南通市| 朔州市| 汤阴县| 久治县| 大理市| 平武县| 观塘区| 虹口区| 长垣县| 五大连池市| 清远市| 礼泉县| 灵山县| 阿克陶县| 文成县| 玉树县| 宣威市| 三穗县|