• <menu id="w2i4a"></menu>
  • logo Fastreport.Net 教程2018(完結(jié))

    文檔首頁(yè)>>Fastreport.Net 教程2018(完結(jié))>>【FastReport.Net】什么是yield return?

    【FastReport.Net】什么是yield return?


    【下載FastReport.Net最新版本】

    yield return運(yùn)算符是使用C#的程序員中最不為人知的運(yùn)算符之一。甚至那些了解它的人也不能完全確定他們正確理解其工作原理。必須糾正這個(gè)惱人的差距。而且,我希望這篇文章可以幫助你。

    yield return運(yùn)算符返回迭代器中的集合項(xiàng),并將當(dāng)前位置移動(dòng)到下一個(gè)元素。yield return運(yùn)算符的存在將該方法轉(zhuǎn)換為迭代器。每次迭代器遇到y(tǒng)ield return時(shí),它都會(huì)返回一個(gè)值。此運(yùn)算符向我們和編譯器發(fā)出信號(hào),表示此表達(dá)式是迭代器。迭代器的任務(wù)是在集合的元素之間移動(dòng)并返回當(dāng)前元素的值。許多人習(xí)慣于在循環(huán)中調(diào)用計(jì)數(shù)器作為迭代器,但事實(shí)并非如此,因?yàn)橛?jì)數(shù)器不返回值。迭代器由編譯器轉(zhuǎn)換為“有限狀態(tài)機(jī)”,跟蹤當(dāng)前位置并知道如何“移動(dòng)”到下一個(gè)位置。在這種情況下,序列元素的值在訪(fǎng)問(wèn)它時(shí)計(jì)算。

    這是迭代器的最簡(jiǎn)單示例:

    public static IEnumerable<int> GetItems()
    {
     foreach (var i in List)
     {
     yield return i;
     }
    }

    迭代器只能返回IEnumerable <>類(lèi)型。

    迭代器是更復(fù)雜的枚舉器模式的語(yǔ)法快捷方式。當(dāng)C#編譯器遇到迭代器時(shí),它會(huì)將其內(nèi)容擴(kuò)展為實(shí)現(xiàn)枚舉器模式的CIL代碼。這種封裝大大節(jié)省了程序員的時(shí)間。迭代器允許您執(zhí)行所謂的“延遲計(jì)算”。這意味著僅在請(qǐng)求時(shí)才評(píng)估元素的值。為了更好地理解收益率回報(bào)如何運(yùn)作,我們將其與傳統(tǒng)周期進(jìn)行比較 通過(guò)示例,一切都變得清晰。

    (1)請(qǐng)注意,使用yield return,我們不需要?jiǎng)?chuàng)建額外的列表來(lái)填充值。因此我們節(jié)省了內(nèi)存,因?yàn)槲覀冎恍枰獌?nèi)存用于集合的當(dāng)前元素。元素處理不分配內(nèi)存,只分配緩存。

    static IEnumerable<int> GetSequence()
     {
     Random rand = new Random();
     List<int> list = new List<int>();
     for (int i = 0; i < 3; i++)
     list.Add(rand.Next());
     return list;
     }
     
     static IEnumerable<int> GetSequence()
     {
     Random rand = new Random();
     for (int i = 0; i < 3; i++)
     yield return rand.Next();
     }

    (2)不計(jì)算整個(gè)枚舉結(jié)果的能力。在這個(gè)例子中,我們無(wú)限地生成數(shù)字:

    IEnumerable<int> GetInfinityWithIterator()
    {
    var i = 0;
    while (true)
    yield return ++i;
    }
     
    IEnumerable<int> GetInfinityWithLoop()
    {
     var i = 0;
     var list = new List<int>();
     while (true)
     list.Add(++i);
     return list;
    }

    下面來(lái)看看他們之間的差異:

    foreach(var item in GetInfinityWithIterator().Take(5))
    {
     Console.WriteLine(item);
    }

    我們使用LINQ運(yùn)算符Take來(lái)限制樣本量。在收益率返回的情況下,循環(huán)在第五個(gè)元素處停止。

    foreach(var item in GetInfinityWithLoop().Take(5))
    {
     Console.WriteLine(item);
    }

    你不能打斷列表填寫(xiě)。結(jié)果,我們得到錯(cuò)誤的內(nèi)存不足。

    (3)執(zhí)行迭代器后調(diào)整集合值的能力。 由于yield在實(shí)際處理時(shí)返回一個(gè)集合元素(例如,當(dāng)在控制臺(tái)中顯示元素的值時(shí)),即使在執(zhí)行迭代器之后,我們也可以更改集合的元素。調(diào)用它時(shí),迭代器實(shí)際上不會(huì)返回實(shí)際值。迭代器知道從哪里獲取值。只有當(dāng)他們真的需要時(shí),他才會(huì)歸還他們。這就是所謂的懶惰負(fù)載。

    IEnumerable<int> MultipleYieldReturn(IEnumerable<int> mass)
    {
     foreach (var item in mass)
     yield return item * item;
    } 
     
    IEnumerable<int> MultipleLoop(IEnumerable<int> mass)
    {
     var list = new List<int>();
     foreach (var item in mass)
     list.Add(item * item);
     return list;
    }

    將調(diào)用這些方法:

     var mass = new List<int>() { 1, 2, 3 }; 
     var MultipleYieldReturn = Helper.MultipleYieldReturn(mass);
     var MultipleLoop = Helper.MultipleLoop(mass);
     
     mass.Add(4);
     Console.WriteLine(string.Join(",",MultipleYieldReturn));
     Console.WriteLine(string.Join(",", MultipleLoop));

    結(jié)果是:

    FastReport

    初始化MultipleYieldReturn和MultipleLoop變量后,我們?cè)傧蚣现刑砑右粋€(gè)元素:mass.Add(4);

     Console.WriteLine(string.Join(",",MultipleYieldReturn));
     Console.WriteLine(string.Join(",", MultipleLoop));

    結(jié)果:

    FastReport

    在將結(jié)果輸出到控制臺(tái)時(shí),集合包含值4.由于yield return在查詢(xún)時(shí)生成值,因此迭代器處理了所有當(dāng)前值。在初始化MultipleLoop變量時(shí)運(yùn)行傳統(tǒng)循環(huán),此時(shí)集合僅包含3個(gè)值。

    (4)具有收益率回報(bào)的異常處理具有細(xì)微差別。yield return語(yǔ)句不能在try-catch部分中使用,只能在try-finally中使用。例如,如何在不知道約束的情況下編寫(xiě):

    public IEnumerable TransformData(List<string> data)
    {
     foreach (string item in data)
     {
     try
     {
     yield return PrepareDataRow(item);
     }
     catch (Exception ex)
     {
     Console.Error.WriteLine(ex.Message);
     }
     }
    }

    在這種情況下,catch塊永遠(yuǎn)不會(huì)捕獲錯(cuò)誤。這都是延遲執(zhí)行收益率回報(bào)的原因。我們只在使用迭代器的數(shù)據(jù)進(jìn)行實(shí)際工作時(shí)才了解錯(cuò)誤。例如,當(dāng)我們將數(shù)據(jù)從迭代器輸出到控制臺(tái)時(shí)。在此之前,迭代器不適用于實(shí)際數(shù)據(jù)。

    如果你仍然需要“Catch”這個(gè)迭代器中的錯(cuò)誤,那么你可以這樣做:

    public IEnumerable TransformData(List<string> data)
    {
     string text;
     foreach (string item in data)
     {
     try
     {
     text = PrepareDataRow(item);
     }
     catch (Exception ex)
     {
     Console.Error.WriteLine(ex.Message);
     continue;
     }
     yield return text;
     }
    }

    yield break類(lèi)似于break運(yùn)算符,它只在迭代器中使用。這是一個(gè)小例子:

    IEnumerable<int> GetNumbers()
    {
    int i = 0;
    while (true)
    {
    if (i = 5)
    yield break;
    yield return i++;
    }
    }

    從示例中可以清楚地看出,當(dāng)達(dá)到5的值時(shí),迭代器將結(jié)束,但在此之前它將正確返回值。

    總結(jié)一下,什么時(shí)候應(yīng)該使用yield return?

    • 列出對(duì)象時(shí)。迭代器將比返回的集合更快地工作。并且內(nèi)存開(kāi)銷(xiāo)較低;
    • 在無(wú)限循環(huán)中。使用Take()方法,您始終可以限制選擇。
    FastReport教程合集
    掃碼咨詢(xún)


    添加微信 立即咨詢(xún)

    電話(huà)咨詢(xún)

    客服熱線(xiàn)
    023-68661681

    TOP
    三级成人熟女影院,欧美午夜成人精品视频,亚洲国产成人乱色在线观看,色中色成人论坛 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();