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

C#中yield關(guān)鍵字之從使用到原理分析

 更新時(shí)間:2025年06月17日 10:15:01   作者:終不似少年游啊  
這篇文章主要介紹了C#中yield關(guān)鍵字之從使用到原理,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

在 C# 編程中,yield關(guān)鍵字是一個(gè)強(qiáng)大且實(shí)用的語法糖,它主要用于簡化迭代器的實(shí)現(xiàn)。通過yield,開發(fā)者可以用更簡潔的代碼實(shí)現(xiàn)延遲執(zhí)行、按需生成數(shù)據(jù)的功能,尤其在處理大數(shù)據(jù)集合或自定義迭代邏輯時(shí)表現(xiàn)出色。

本文將從基礎(chǔ)概念入手,逐步深入到yield的底層實(shí)現(xiàn)原理,幫助讀者全面掌握這一重要特性。

一、yield 關(guān)鍵字的基本概念

在 C# 中,yield關(guān)鍵字主要用于定義迭代器方法,它有兩種形式:

  • yield return:返回一個(gè)值并暫停方法執(zhí)行,保存當(dāng)前狀態(tài)
  • yield break:終止迭代過程

下面通過一個(gè)簡單示例對比使用yield和傳統(tǒng)方式實(shí)現(xiàn)迭代的差異:

// 傳統(tǒng)方式:返回完整集合
public static List<int> GetNumbers()
{
    List<int> numbers = new List<int>();
    numbers.Add(1);
    numbers.Add(2);
    numbers.Add(3);
    return numbers;
}

// 使用yield:延遲生成值
public static IEnumerable<int> GetNumbers()
{
    yield return 1;
    yield return 2;
    yield return 3;
}

從這個(gè)例子可以看出,使用yield后代碼變得更加簡潔,不需要顯式創(chuàng)建和管理集合。

二、yield 的核心特性:延遲執(zhí)行與狀態(tài)管理

1. 延遲執(zhí)行機(jī)制

yield最顯著的特性是延遲執(zhí)行(Lazy Evaluation)。當(dāng)調(diào)用包含yield的方法時(shí),方法體并不會立即執(zhí)行,而是返回一個(gè)實(shí)現(xiàn)了IEnumerable<T>接口的迭代器對象。

只有當(dāng)客戶端代碼通過foreach或直接調(diào)用MoveNext()方法時(shí),方法體才會真正執(zhí)行。

下面的示例展示了延遲執(zhí)行的效果:

public static IEnumerable<int> GetNumbers()
{
    Console.WriteLine("開始執(zhí)行");
    yield return 1;
    Console.WriteLine("返回了第一個(gè)值");
    yield return 2;
    Console.WriteLine("返回了第二個(gè)值");
    yield return 3;
    Console.WriteLine("返回了第三個(gè)值");
}

// 調(diào)用代碼
var numbers = GetNumbers();
Console.WriteLine("迭代器已經(jīng)創(chuàng)建");

foreach (int number in numbers)
{
    Console.WriteLine($"獲取到值: {number}");
    Console.WriteLine("--------");
}

輸出結(jié)果如下:

迭代器已經(jīng)創(chuàng)建
開始執(zhí)行
獲取到值: 1
--------
返回了第一個(gè)值
獲取到值: 2
--------
返回了第二個(gè)值
獲取到值: 3
--------
返回了第三個(gè)值

從輸出可以看出,直到第一次調(diào)用MoveNext()(通過foreach觸發(fā))時(shí),方法體才開始執(zhí)行,并且每次yield后會暫停執(zhí)行,等待下一次請求。

2. 自動狀態(tài)管理

yield方法會自動保存局部變量的狀態(tài)。每次調(diào)用MoveNext()時(shí),方法會從上一次yield的位置繼續(xù)執(zhí)行,而不是從頭開始。

這種狀態(tài)管理是由編譯器自動實(shí)現(xiàn)的,開發(fā)者無需手動維護(hù)。

三、yield 的底層實(shí)現(xiàn)原理

1. 編譯器魔法:狀態(tài)機(jī)轉(zhuǎn)換

當(dāng)編譯器遇到包含yield的方法時(shí),會進(jìn)行以下轉(zhuǎn)換:

  1. 創(chuàng)建狀態(tài)機(jī)類:生成一個(gè)實(shí)現(xiàn)了IEnumerable<T>IEnumerator<T>接口的嵌套類
  2. 分解方法體:將原方法體分解為多個(gè)狀態(tài),每個(gè)yield return成為一個(gè)狀態(tài)轉(zhuǎn)換點(diǎn)
  3. 實(shí)現(xiàn)狀態(tài)管理:通過狀態(tài)變量(如整數(shù))記錄當(dāng)前執(zhí)行位置,保存所有局部變量

下面是一個(gè)簡化的狀態(tài)機(jī)實(shí)現(xiàn)示例(實(shí)際編譯器生成的代碼更復(fù)雜):

private sealed class IteratorStateMachine : IEnumerator<int>, IEnumerable<int>
{
    // 狀態(tài)標(biāo)識
    private int state;
    // 當(dāng)前返回值
    private int current;
    
    // 每次調(diào)用GetEnumerator()時(shí)創(chuàng)建新實(shí)例
    public IteratorStateMachine(int state) => this.state = state;
    
    // IEnumerable接口實(shí)現(xiàn)
    public IEnumerator<int> GetEnumerator() => this;
    object IEnumerator.Current => current;
    public int Current => current;
    
    // 核心方法:控制狀態(tài)轉(zhuǎn)換
    public bool MoveNext()
    {
        switch (state)
        {
            case 0: // 初始狀態(tài)
                state = -1; // 默認(rèn)標(biāo)記為完成
                current = 1; // 設(shè)置第一個(gè)返回值
                state = 1;   // 跳轉(zhuǎn)到第一個(gè)yield后的狀態(tài)
                return true;
                
            case 1: // 第一個(gè)yield后
                state = -1;
                current = 2;
                state = 2;
                return true;
                
            case 2: // 第二個(gè)yield后
                state = -1;
                current = 3;
                state = 3;
                return true;
                
            case 3: // 第三個(gè)yield后
                return false; // 迭代結(jié)束
                
            default:
                return false;
        }
    }
    
    // 其他接口方法
    public void Dispose() => state = -1;
    public void Reset() => throw new NotSupportedException();
}

2. 執(zhí)行流程解析

  1. 調(diào)用方法時(shí):返回狀態(tài)機(jī)的一個(gè)實(shí)例,初始狀態(tài)為 0
  2. 第一次調(diào)用 MoveNext ():執(zhí)行狀態(tài) 0 的代碼,設(shè)置 current 值,更新狀態(tài)為 1
  3. 后續(xù)調(diào)用 MoveNext ():根據(jù)當(dāng)前狀態(tài)執(zhí)行對應(yīng)的代碼片段,直到狀態(tài)變?yōu)橥瓿桑?1)

3. 資源管理與異常處理

  • using 語句:如果yield方法中使用了using語句,狀態(tài)機(jī)的Dispose()方法會確保資源被正確釋放
  • 異常處理yield方法中不能有try-catch塊(因?yàn)闋顟B(tài)機(jī)無法跨yield保存異常上下文),但可以有try-finally

四、yield 的典型應(yīng)用場景

1. 大數(shù)據(jù)集合處理

當(dāng)處理大量數(shù)據(jù)時(shí),yield可以顯著節(jié)省內(nèi)存,實(shí)現(xiàn)按需加載:

public static IEnumerable<DataItem> LoadLargeData()
{
    using (var connection = new SqlConnection(connectionString))
    {
        connection.Open();
        using (var command = new SqlCommand(query, connection))
        {
            using (var reader = command.ExecuteReader())
            {
                while (reader.Read())
                {
                    yield return new DataItem
                    {
                        Id = reader.GetInt32(0),
                        Name = reader.GetString(1)
                    };
                }
            }
        }
    }
}

2. 自定義迭代邏輯

通過yield可以輕松實(shí)現(xiàn)復(fù)雜的迭代邏輯,例如過濾、轉(zhuǎn)換數(shù)據(jù):

public class MyCollection
{
    private readonly int[] _items;

    public MyCollection(int[] items)
    {
        _items = items;
    }

    public IEnumerable<int> EvenNumbers()
    {
        foreach (var item in _items)
        {
            if (item % 2 == 0)
            {
                yield return item;
            }
        }
    }
}

3. 無限序列生成

生成無限序列(如斐波那契數(shù)列)時(shí),yield是理想選擇:

public static IEnumerable<int> Fibonacci()
{
    int a = 0, b = 1;
    while (true)
    {
        yield return a;
        int temp = a;
        a = b;
        b = temp + b;
    }
}

五、使用 yield 的注意事項(xiàng)

  1. 返回類型限制yield方法的返回類型必須是IEnumerable<T>IEnumerator<T>
  2. 不能在匿名方法中使用yield不能用于 lambda 表達(dá)式或匿名方法
  3. 異常處理限制:不能有try-catch塊,但可以有try-finally
  4. 性能考慮:多次枚舉可能導(dǎo)致重復(fù)計(jì)算,可考慮使用ToList()緩存結(jié)果

六、總結(jié)

yield關(guān)鍵字是 C# 語言中一個(gè)強(qiáng)大的語法糖,它通過狀態(tài)機(jī)模式自動實(shí)現(xiàn)了復(fù)雜的迭代器邏輯,讓開發(fā)者可以用更簡潔的代碼實(shí)現(xiàn)延遲執(zhí)行和狀態(tài)管理。理解yield的底層原理有助于更高效地使用它,并避免潛在的性能問題。

在實(shí)際開發(fā)中,yield特別適合處理大數(shù)據(jù)集合、實(shí)現(xiàn)自定義迭代邏輯和生成無限序列等場景。通過合理使用yield,可以顯著提升代碼的可讀性和性能。

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Unity登錄注冊時(shí)限制發(fā)送驗(yàn)證碼次數(shù)功能的解決方法

    Unity登錄注冊時(shí)限制發(fā)送驗(yàn)證碼次數(shù)功能的解決方法

    這篇文章主要為大家詳細(xì)介紹了Unity登錄注冊時(shí)限制發(fā)送驗(yàn)證碼次數(shù)功能的解決方案,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-01-01
  • LINQ基礎(chǔ)之From和GroupBy子句

    LINQ基礎(chǔ)之From和GroupBy子句

    這篇文章介紹了LINQ使用From和GroupBy子句的方法,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-04-04
  • Unity實(shí)現(xiàn)物體左右移動效果

    Unity實(shí)現(xiàn)物體左右移動效果

    這篇文章主要為大家詳細(xì)介紹了Unity實(shí)現(xiàn)物體左右移動效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-08-08
  • 從C#程序中調(diào)用非受管DLLs的方法

    從C#程序中調(diào)用非受管DLLs的方法

    這篇文章主要介紹了從C#程序中調(diào)用非受管DLLs的方法,是非常實(shí)用的技巧,有助于深入理解Windows程序設(shè)計(jì),需要的朋友可以參考下
    2014-10-10
  • C#實(shí)現(xiàn)將json轉(zhuǎn)換為DataTable的方法

    C#實(shí)現(xiàn)將json轉(zhuǎn)換為DataTable的方法

    這篇文章主要介紹了C#實(shí)現(xiàn)將json轉(zhuǎn)換為DataTable的方法,涉及C#操作json及DataTable的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-03-03
  • C# WinForm實(shí)現(xiàn)Socket異步通訊的步驟詳解

    C# WinForm實(shí)現(xiàn)Socket異步通訊的步驟詳解

    Socket通訊是網(wǎng)絡(luò)編程中非?;A(chǔ)且重要的一部分,它為應(yīng)用程序提供了基于TCP/IP協(xié)議進(jìn)行數(shù)據(jù)傳輸?shù)哪芰?本文將詳細(xì)介紹如何在C#的WinForm應(yīng)用程序中實(shí)現(xiàn)Socket的異步通訊,希望能為有需要的開發(fā)提供一些參考,需要的朋友可以參考下
    2025-07-07
  • C#中事件的動態(tài)調(diào)用實(shí)現(xiàn)方法

    C#中事件的動態(tài)調(diào)用實(shí)現(xiàn)方法

    這篇文章主要介紹了C#中事件的動態(tài)調(diào)用實(shí)現(xiàn)方法,對比傳統(tǒng)思路優(yōu)劣給出了一個(gè)新的解決方案,需要的朋友可以參考下
    2014-09-09
  • C#實(shí)現(xiàn)FTP客戶端的案例

    C#實(shí)現(xiàn)FTP客戶端的案例

    這篇文章主要為大家詳細(xì)介紹了C#實(shí)現(xiàn)FTP客戶端的小案例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-07-07
  • C#中的并發(fā)集合Concurrent類

    C#中的并發(fā)集合Concurrent類

    這篇文章介紹了C#中的并發(fā)集合Concurrent類,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-05-05
  • C#調(diào)用Oracle存儲過程方法介紹(附源碼)

    C#調(diào)用Oracle存儲過程方法介紹(附源碼)

    這篇文章介紹了C#調(diào)用Oracle存儲過程的方法,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-03-03

最新評論

绥德县| 明水县| 图们市| 张家川| 来宾市| 富平县| 临夏市| 云林县| 梨树县| 东海县| 无锡市| 英吉沙县| 马公市| 霸州市| 牙克石市| 四平市| 东兰县| 永昌县| 剑河县| 日土县| 莲花县| 衡水市| 沅江市| 吉木萨尔县| 依安县| 恩平市| 南和县| 林西县| 稻城县| 自治县| 曲沃县| 偃师市| 扶风县| 徐水县| 宿迁市| 杭锦旗| 樟树市| 左贡县| 连山| 呼玛县| 虎林市|