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

關(guān)于C#中yield?return用法的思考

 更新時(shí)間:2023年05月31日 09:31:32   作者:yi念之間  
在這篇文章中,我們將深入討論?C#?中yield?return的機(jī)制和用法,幫助您更好地理解這個(gè)強(qiáng)大的功能,并在實(shí)際開(kāi)發(fā)中靈活使用它,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

前言

當(dāng)我們編寫(xiě) C# 代碼時(shí),經(jīng)常需要處理大量的數(shù)據(jù)集合。在傳統(tǒng)的方式中,我們往往需要先將整個(gè)數(shù)據(jù)集合加載到內(nèi)存中,然后再進(jìn)行操作。但是如果數(shù)據(jù)集合非常大,這種方式就會(huì)導(dǎo)致內(nèi)存占用過(guò)高,甚至可能導(dǎo)致程序崩潰。

C# 中的yield return機(jī)制可以幫助我們解決這個(gè)問(wèn)題。通過(guò)使用yield return,我們可以將數(shù)據(jù)集合按需生成,而不是一次性生成整個(gè)數(shù)據(jù)集合。這樣可以大大減少內(nèi)存占用,并且提高程序的性能。

在本文中,我們將深入討論 C# 中yield return的機(jī)制和用法,幫助您更好地理解這個(gè)強(qiáng)大的功能,并在實(shí)際開(kāi)發(fā)中靈活使用它。

使用方式

上面我們提到了yield return將數(shù)據(jù)集合按需生成,而不是一次性生成整個(gè)數(shù)據(jù)集合。接下來(lái)通過(guò)一個(gè)簡(jiǎn)單的示例,我們看一下它的工作方式是什么樣的,以便加深對(duì)它的理解

foreach (var num in GetInts())
{
    Console.WriteLine("外部遍歷了:{0}", num);
}
IEnumerable<int> GetInts()
{
    for (int i = 0; i < 5; i++)
    {
        Console.WriteLine("內(nèi)部遍歷了:{0}", i);
        yield return i;
    }
}

首先,在GetInts方法中,我們使用yield return關(guān)鍵字來(lái)定義一個(gè)迭代器。這個(gè)迭代器可以按需生成整數(shù)序列。在每次循環(huán)時(shí),使用yield return返回當(dāng)前的整數(shù)。通過(guò)1foreach循環(huán)來(lái)遍歷 GetInts方法返回的整數(shù)序列。在迭代時(shí)GetInts方法會(huì)被執(zhí)行,但是不會(huì)將整個(gè)序列加載到內(nèi)存中。而是在需要時(shí),按需生成序列中的每個(gè)元素。在每次迭代時(shí),會(huì)輸出當(dāng)前迭代的整數(shù)對(duì)應(yīng)的信息。所以輸出的結(jié)果為

內(nèi)部遍歷了:0
外部遍歷了:0
內(nèi)部遍歷了:1
外部遍歷了:1
內(nèi)部遍歷了:2
外部遍歷了:2
內(nèi)部遍歷了:3
外部遍歷了:3
內(nèi)部遍歷了:4
外部遍歷了:4

可以看到,整數(shù)序列是按需生成的,并且在每次生成時(shí)都會(huì)輸出相應(yīng)的信息。這種方式可以大大減少內(nèi)存占用,并且提高程序的性能。當(dāng)然從c# 8開(kāi)始異步迭代的方式同樣支持

await foreach (var num in GetIntsAsync())
{
    Console.WriteLine("外部遍歷了:{0}", num);
}
async IAsyncEnumerable<int> GetIntsAsync()
{
    for (int i = 0; i < 5; i++)
    {
        await Task.Yield();
        Console.WriteLine("內(nèi)部遍歷了:{0}", i);
        yield return i;
    }
}

和上面不同的是,如果需要用異步的方式,我們需要返回IAsyncEnumerable類型,這種方式的執(zhí)行結(jié)果和上面同步的方式執(zhí)行的結(jié)果是一致的,我們就不做展示了。上面我們的示例都是基于循環(huán)持續(xù)迭代的,其實(shí)使用yield return的方式還可以按需的方式去輸出,這種方式適合靈活迭代的方式。如下示例所示

foreach (var num in GetInts())
{
    Console.WriteLine("外部遍歷了:{0}", num);
}
IEnumerable<int> GetInts()
{
    Console.WriteLine("內(nèi)部遍歷了:0");
    yield return 0;
    Console.WriteLine("內(nèi)部遍歷了:1");
    yield return 1;
    Console.WriteLine("內(nèi)部遍歷了:2");
    yield return 2;
}

foreach循環(huán)每次會(huì)調(diào)用GetInts()方法,GetInts()方法的內(nèi)部便使用yield return關(guān)鍵字返回一個(gè)結(jié)果。每次遍歷都會(huì)去執(zhí)行下一個(gè)yield return。所以上面代碼輸出的結(jié)果是

內(nèi)部遍歷了:0
外部遍歷了:0
內(nèi)部遍歷了:1
外部遍歷了:1
內(nèi)部遍歷了:2
外部遍歷了:2

探究本質(zhì)

上面我們展示了yield return如何使用的示例,它是一種延遲加載的機(jī)制,它可以讓我們逐個(gè)地處理數(shù)據(jù),而不是一次性地將所有數(shù)據(jù)讀取到內(nèi)存中。接下來(lái)我們就來(lái)探究一下神奇操作的背后到底是如何實(shí)現(xiàn)的,方便讓大家更清晰的了解迭代體系相關(guān)。

foreach本質(zhì)

首先我們來(lái)看一下foreach為什么可以遍歷,也就是如果可以被foreach遍歷的對(duì)象,被遍歷的操作需要滿足哪些條件,這個(gè)時(shí)候我們可以反編譯工具來(lái)看一下編譯后的代碼是什么樣子的,相信大家最熟悉的就是List<T>集合的遍歷方式了,那我們就用List<T>的示例來(lái)演示一下

List<int> ints = new List<int>();
foreach(int item in ints)
{
    Console.WriteLine(item);
}

上面的這段代碼很簡(jiǎn)單,我們也沒(méi)有給它任何初始化的數(shù)據(jù),這樣可以排除干擾,讓我們能更清晰的看到反編譯的結(jié)果,排除其他干擾。它反編譯后的代碼是這樣的

List<int> list = new List<int>();
List<int>.Enumerator enumerator = list.GetEnumerator();
try
{
    while (enumerator.MoveNext())
    {
        int current = enumerator.Current;
        Console.WriteLine(current);
    }
}
finally
{
    ((IDisposable)enumerator).Dispose();
}

可以反編譯代碼的工具有很多,我用的比較多的一般是ILSpy、dnSpy、dotPeek和在線c#反編譯網(wǎng)站sharplab.io,其中dnSpy還可以調(diào)試反編譯的代碼。

通過(guò)上面的反編譯之后的代碼我們可以看到foreach會(huì)被編譯成一個(gè)固定的結(jié)構(gòu),也就是我們經(jīng)常提及的設(shè)計(jì)模式中的迭代器模式結(jié)構(gòu)

Enumerator enumerator = list.GetEnumerator();
while (enumerator.MoveNext())
{
   var current = enumerator.Current;
}

通過(guò)這段固定的結(jié)構(gòu)我們總結(jié)一下foreach的工作原理

  • 可以被foreach的對(duì)象需要要包含GetEnumerator()方法
  • 迭代器對(duì)象包含MoveNext()方法和Current屬性
  • MoveNext()方法返回bool類型,判斷是否可以繼續(xù)迭代。Current屬性返回當(dāng)前的迭代結(jié)果。

我們可以看一下List<T>類可迭代的源碼結(jié)構(gòu)是如何實(shí)現(xiàn)的

public class List<T> : IList<T>, IList, IReadOnlyList<T>
{
    public Enumerator GetEnumerator() => new Enumerator(this);
    IEnumerator<T> IEnumerable<T>.GetEnumerator() => Count == 0 ? SZGenericArrayEnumerator<T>.Empty : GetEnumerator();
    IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable<T>)this).GetEnumerator();
    public struct Enumerator : IEnumerator<T>, IEnumerator
    {
        public T Current => _current!;
        public bool MoveNext()
        {
        }
    }
}

這里涉及到了兩個(gè)核心的接口IEnumerable<IEnumerator,他們兩個(gè)定義了可以實(shí)現(xiàn)迭代的能力抽象,實(shí)現(xiàn)方式如下

public interface IEnumerable
{
    IEnumerator GetEnumerator();
}
public interface IEnumerator
{
    bool MoveNext();
    object Current{ get; }
    void Reset();
}

如果類實(shí)現(xiàn)IEnumerable接口并實(shí)現(xiàn)了GetEnumerator()方法便可以被foreach,迭代的對(duì)象是IEnumerator類型,包含一個(gè)MoveNext()方法和Current屬性。上面的接口是原始對(duì)象的方式,這種操作都是針對(duì)object類型集合對(duì)象。我們實(shí)際開(kāi)發(fā)過(guò)程中大多數(shù)都是使用的泛型集合,當(dāng)然也有對(duì)應(yīng)的實(shí)現(xiàn)方式,如下所示

public interface IEnumerable<out T> : IEnumerable
{
    new IEnumerator<T> GetEnumerator();
}
public interface IEnumerator<out T> : IDisposable, IEnumerator
{
    new T Current{ get; }
}

可以被foreach迭代并不意味著一定要去實(shí)現(xiàn)IEnumerable接口,這只是給我們提供了一個(gè)可以被迭代的抽象的能力。只要類中包含GetEnumerator()方法并返回一個(gè)迭代器,迭代器里包含返回bool類型的MoveNext()方法和獲取當(dāng)前迭代對(duì)象的Current屬性即可。

yield return本質(zhì)

上面我們看到了可以被foreach迭代的本質(zhì)是什么,那么yield return的返回值可以被IEnumerable<T>接收說(shuō)明其中必有蹊蹺,我們反編譯一下我們上面的示例看一下反編譯之后代碼,為了方便大家對(duì)比反編譯結(jié)果,這里我把上面的示例再次粘貼一下

foreach (var num in GetInts())
{
    Console.WriteLine("外部遍歷了:{0}", num);
}
IEnumerable<int> GetInts()
{
    for (int i = 0; i < 5; i++)
    {
        Console.WriteLine("內(nèi)部遍歷了:{0}", i);
        yield return i;
    }
}

它的反編譯結(jié)果,這里咱們就不全部展示了,只展示一下核心的邏輯

//foeach編譯后的結(jié)果
IEnumerator<int> enumerator = GetInts().GetEnumerator();
try
{
    while (enumerator.MoveNext())
    {
        int current = enumerator.Current;
        Console.WriteLine("外部遍歷了:{0}", current);
    }
}
finally
{
    if (enumerator != null)
    {
        enumerator.Dispose();
    }
}
//GetInts方法編譯后的結(jié)果
private IEnumerable<int> GetInts()
{
    <GetInts>d__1 <GetInts>d__ = new <GetInts>d__1(-2);
    <GetInts>d__.<>4__this = this;
    return <GetInts>d__;
}

這里我們可以看到GetInts()方法里原來(lái)的代碼不見(jiàn)了,而是多了一個(gè)<GetInts>d__1l類型,也就是說(shuō)yield return本質(zhì)是語(yǔ)法糖。我們看一下<GetInts>d__1類的實(shí)現(xiàn)

//生成的類即實(shí)現(xiàn)了IEnumerable接口也實(shí)現(xiàn)了IEnumerator接口
//說(shuō)明它既包含了GetEnumerator()方法,也包含MoveNext()方法和Current屬性
private sealed class <>GetIntsd__1 : IEnumerable<int>, IEnumerable, IEnumerator<int>, IEnumerator, IDisposable
{
    private int <>1__state;
    //當(dāng)前迭代結(jié)果
    private int <>2__current;
    private int <>l__initialThreadId;
    public C <>4__this;
    private int <i>5__1;
    //當(dāng)前迭代到的結(jié)果
    int IEnumerator<int>.Current
    {
        get{ return <>2__current; }
    }
    //當(dāng)前迭代到的結(jié)果
    object IEnumerator.Current
    {
        get{ return <>2__current; }
    }
    //構(gòu)造函數(shù)包含狀態(tài)字段,變向說(shuō)明靠狀態(tài)機(jī)去實(shí)現(xiàn)核心流程流轉(zhuǎn)
    public <GetInts>d__1(int <>1__state)
    {
        this.<>1__state = <>1__state;
        <>l__initialThreadId = Environment.CurrentManagedThreadId;
    }
    //核心方法MoveNext
    private bool MoveNext()
    {
        int num = <>1__state;
        if (num != 0)
        {
            if (num != 1)
            {
                return false;
            }
            //控制狀態(tài)
            <>1__state = -1;
            //自增 也就是代碼里循環(huán)的i++
            <i>5__1++;
        }
        else
        {
            <>1__state = -1;
            <i>5__1 = 0;
        }
        //循環(huán)終止條件 上面循環(huán)里的i<5
        if (<i>5__1 < 5)
        {
            Console.WriteLine("內(nèi)部遍歷了:{0}", <i>5__1);
            //把當(dāng)前迭代結(jié)果賦值給Current屬性
            <>2__current = <i>5__1;
            <>1__state = 1;
            //說(shuō)明可以繼續(xù)迭代
            return true;
        }
        //迭代結(jié)束
        return false;
    }
    //IEnumerator的MoveNext方法
    bool IEnumerator.MoveNext()
    {
        return this.MoveNext();
    }
    //IEnumerable的IEnumerable方法
    IEnumerator<int> IEnumerable<int>.IEnumerable()
    {
        //實(shí)例化<GetInts>d__1實(shí)例
        <GetInts>d__1 <GetInts>d__;
        if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
        {
            <>1__state = 0;
            <GetInts>d__ = this;
        }
        else
        {
            //給狀態(tài)機(jī)初始化
            <GetInts>d__ = new <GetInts>d__1(0);
            <GetInts>d__.<>4__this = <>4__this;
        }
        //因?yàn)?lt;GetInts>d__1實(shí)現(xiàn)了IEnumerator接口所以可以直接返回
        return <GetInts>d__;
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        //因?yàn)?lt;GetInts>d__1實(shí)現(xiàn)了IEnumerator接口所以可以直接轉(zhuǎn)換
        return ((IEnumerable<int>)this).GetEnumerator();
    }
    void IEnumerator.Reset()
    {
    }
    void IDisposable.Dispose()
    {
    }
}

通過(guò)它生成的類我們可以看到,該類即實(shí)現(xiàn)了IEnumerable接口也實(shí)現(xiàn)了IEnumerator接口說(shuō)明它既包含了GetEnumerator()方法,也包含MoveNext()方法和Current屬性。用這一個(gè)類就可以滿足可被foeach迭代的核心結(jié)構(gòu)。我們手動(dòng)寫(xiě)的for代碼被包含到了MoveNext()方法里,它包含了定義的狀態(tài)機(jī)制代碼,并且根據(jù)當(dāng)前的狀態(tài)機(jī)代碼將迭代移動(dòng)到下一個(gè)元素。我們大概講解一下我們的for代碼被翻譯到MoveNext()方法里的執(zhí)行流程

  • 首次迭代時(shí)<>1__state被初始化成0,代表首個(gè)被迭代的元素,這個(gè)時(shí)候Current初始值為0,循環(huán)控制變量<i>5__1初始值也為0。
  • 判斷是否滿足終止條件,不滿足則執(zhí)行循環(huán)里的邏輯。并更改裝填機(jī)<>1__state為1,代表首次迭代執(zhí)行完成。
  • 循環(huán)控制變量<i>5__1繼續(xù)自增并更改并更改裝填機(jī)<>1__state為-1,代表可持續(xù)迭代。并循環(huán)執(zhí)行循環(huán)體的自定義邏輯。
  • 不滿足迭代條件則返回false,也就是代表了MoveNext()以不滿足迭代條件while (enumerator.MoveNext())邏輯終止。

上面我們還展示了另一種yield return的方式,就是同一個(gè)方法里包含多個(gè)yield return的形式

IEnumerable<int> GetInts()
{
    Console.WriteLine("內(nèi)部遍歷了:0");
    yield return 0;
    Console.WriteLine("內(nèi)部遍歷了:1");
    yield return 1;
    Console.WriteLine("內(nèi)部遍歷了:2");
    yield return 2;
}

上面這段代碼反編譯的結(jié)果如下所示,這里咱們只展示核心的方法MoveNext()的實(shí)現(xiàn)

private bool MoveNext()
{
    switch (<>1__state)
    {
        default:
            return false;
        case 0:
            <>1__state = -1;
            Console.WriteLine("內(nèi)部遍歷了:0");
            <>2__current = 0;
            <>1__state = 1;
            return true;
        case 1:
            <>1__state = -1;
            Console.WriteLine("內(nèi)部遍歷了:1");
            <>2__current = 1;
            <>1__state = 2;
            return true;
        case 2:
            <>1__state = -1;
            Console.WriteLine("內(nèi)部遍歷了:2");
            <>2__current = 2;
            <>1__state = 3;
            return true;
        case 3:
            <>1__state = -1;
            return false;
    }
}

通過(guò)編譯后的代碼我們可以看到,多個(gè)yield return的形式會(huì)被編譯成switch...case的形式,有幾個(gè)yield return則會(huì)編譯成n+1個(gè)case,多出來(lái)的一個(gè)case則代表的MoveNext()終止條件,也就是返回false的條件。其它的case則返回true表示可以繼續(xù)迭代。

IAsyncEnumerable接口

上面我們展示了同步yield return方式,c# 8開(kāi)始新增了IAsyncEnumerable<T>接口,用于完成異步迭代,也就是迭代器邏輯里包含異步邏輯的場(chǎng)景。IAsyncEnumerable<T>接口的實(shí)現(xiàn)代碼如下所示

public interface IAsyncEnumerable<out T>
{
    IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default);
}
public interface IAsyncEnumerator<out T> : IAsyncDisposable
{
    ValueTask<bool> MoveNextAsync();
    T Current { get; }
}

它最大的不同則是同步的IEnumerator包含的是MoveNext()方法返回的是bool,IAsyncEnumerator接口包含的是MoveNextAsync()異步方法,返回的是ValueTask<bool>類型。所以上面的示例代碼

await foreach (var num in GetIntsAsync())
{
    Console.WriteLine("外部遍歷了:{0}", num);
}

所以這里的await雖然是加在foreach上面,但是實(shí)際作用的則是每一次迭代執(zhí)行的MoveNextAsync()方法??梢源笾吕斫鉃橄旅娴墓ぷ鞣绞?/p>

IAsyncEnumerator<int> enumerator = list.GetAsyncEnumerator();
while (enumerator.MoveNextAsync().GetAwaiter().GetResult())
{
   var current = enumerator.Current;
}

當(dāng)然,實(shí)際編譯成的代碼并不是這個(gè)樣子的,我們?cè)谥暗奈恼?lt;研究c#異步操作async await狀態(tài)機(jī)的總結(jié)>一文中講解過(guò)async await會(huì)被編譯成IAsyncStateMachine異步狀態(tài)機(jī),所以IAsyncEnumerator<T>結(jié)合yield return的實(shí)現(xiàn)比同步的方式更加復(fù)雜而且包含更多的代碼,不過(guò)實(shí)現(xiàn)原理可以結(jié)合同步的方式類比一下,但是要同時(shí)了解異步狀態(tài)機(jī)的實(shí)現(xiàn),這里咱們就不過(guò)多展示異步y(tǒng)ield return的編譯后實(shí)現(xiàn)了,有興趣的同學(xué)可以自行了解一下。

foreach增強(qiáng)

c# 9增加了對(duì)foreach的增強(qiáng)的功能,即通過(guò)擴(kuò)展方法的形式,對(duì)原本具備包含foreach能力的對(duì)象增加GetEnumerator()方法,使得普通類在不具備foreach的能力的情況下也可以使用來(lái)迭代。它的使用方式如下

Foo foo = new Foo();
foreach (int item in foo)
{
    Console.WriteLine(item);
}
public class Foo
{
    public List<int> Ints { get; set; } = new List<int>();
}
public static class Bar
{
    //給Foo定義擴(kuò)展方法
    public static IEnumerator<int> GetEnumerator(this Foo foo)
    {
        foreach (int item in foo.Ints)
        {
            yield return item;
        }
    }
}

這個(gè)功能確實(shí)比較強(qiáng)大,滿足開(kāi)放封閉原則,我們可以在不修改原始代碼的情況,增強(qiáng)代碼的功能,可以說(shuō)是非常的實(shí)用。我們來(lái)看一下它的編譯后的結(jié)果是啥

Foo foo = new Foo();
IEnumerator<int> enumerator = Bar.GetEnumerator(foo);
try
{
    while (enumerator.MoveNext())
    {
        int current = enumerator.Current;
        Console.WriteLine(current);
    }
}
finally
{
    if (enumerator != null)
    {
        enumerator.Dispose();
    }
}

這里我們看到擴(kuò)展方法GetEnumerator()本質(zhì)也是語(yǔ)法糖,會(huì)把擴(kuò)展能力編譯成擴(kuò)展類.GetEnumerator(被擴(kuò)展實(shí)例)的方式。也就是我們寫(xiě)代碼時(shí)候的原始方式,只是編譯器幫我們生成了它的調(diào)用方式。接下來(lái)我們看一下GetEnumerator()擴(kuò)展方法編譯成了什么

public static IEnumerator<int> GetEnumerator(Foo foo)
{
    <GetEnumerator>d__0 <GetEnumerator>d__ = new <GetEnumerator>d__0(0);
    <GetEnumerator>d__.foo = foo;
    return <GetEnumerator>d__;
}

看到這個(gè)代碼是不是覺(jué)得很眼熟了,不錯(cuò)和上面yield return本質(zhì)這一節(jié)里講到的語(yǔ)法糖生成方式是一樣的了,同樣的編譯時(shí)候也是生成了一個(gè)對(duì)應(yīng)類,這里的類是<GetEnumerator>d__0,我們看一下該類的結(jié)構(gòu)

private sealed class <GetEnumerator>d__0 : IEnumerator<int>, IEnumerator, IDisposable
{
    private int <>1__state;
    private int <>2__current;
    public Foo foo;
    private List<int>.Enumerator <>s__1;
    private int <item>5__2;
    int IEnumerator<int>.Current
    {
        get{ return <>2__current; }
    }
    object IEnumerator.Current
    {
        get{ return <>2__current; }
    }
    public <GetEnumerator>d__0(int <>1__state)
    {
        this.<>1__state = <>1__state;
    }
    private bool MoveNext()
    {
        try
        {
            int num = <>1__state;
            if (num != 0)
            {
                if (num != 1)
                {
                    return false;
                }
                <>1__state = -3;
            }
            else
            {
                <>1__state = -1;
                //因?yàn)槭纠械腎nts我們使用的是List<T>
                <>s__1 = foo.Ints.GetEnumerator();
                <>1__state = -3;
            }
            //因?yàn)樯厦娴臄U(kuò)展方法里使用的是foreach遍歷方式
            //這里也被編譯成了實(shí)際生產(chǎn)方式
            if (<>s__1.MoveNext())
            {
                <item>5__2 = <>s__1.Current;
                <>2__current = <item>5__2;
                <>1__state = 1;
                return true;
            }
            <>m__Finally1();
            <>s__1 = default(List<int>.Enumerator);
            return false;
        }
        catch
        {
            ((IDisposable)this).Dispose();
            throw;
        }
    }
    bool IEnumerator.MoveNext()
    {
        return this.MoveNext();
    }
    void IDisposable.Dispose()
    {
    }
    void IEnumerator.Reset()
    {
    }
    private void <>m__Finally1()
    {
    }
}

看到編譯器生成的代碼,我們可以看到yield return生成的代碼結(jié)構(gòu)都是一樣的,只是MoveNext()里的邏輯取決于我們寫(xiě)代碼時(shí)候的具體邏輯,不同的邏輯生成不同的代碼。這里咱們就不在講解它生成的代碼了,因?yàn)楹蜕厦嬖蹅冎v解的代碼邏輯是差不多的。

總結(jié)

通過(guò)本文我們介紹了c#中的yield return語(yǔ)法,并探討了由它帶來(lái)的一些思考。我們通過(guò)一些簡(jiǎn)單的例子,展示了yield return的使用方式,知道了迭代器來(lái)是如何按需處理大量數(shù)據(jù)。同時(shí),我們通過(guò)分析foreach迭代和yield return語(yǔ)法的本質(zhì),講解了它們的實(shí)現(xiàn)原理和底層機(jī)制。好在涉及到的知識(shí)整體比較簡(jiǎn)單,仔細(xì)閱讀相關(guān)實(shí)現(xiàn)代碼的話相信會(huì)了解背后的實(shí)現(xiàn)原理,這里就不過(guò)多贅述了。

到此這篇關(guān)于關(guān)于C#中yield return用法的思考的文章就介紹到這了,更多相關(guān)C# yield return內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Unity 如何通過(guò)反射給gameObject添加組件

    Unity 如何通過(guò)反射給gameObject添加組件

    這篇文章主要介紹了Unity 通過(guò)反射給gameObject添加組件的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-04-04
  • C#數(shù)據(jù)結(jié)構(gòu)之堆棧(Stack)實(shí)例詳解

    C#數(shù)據(jù)結(jié)構(gòu)之堆棧(Stack)實(shí)例詳解

    這篇文章主要介紹了C#數(shù)據(jù)結(jié)構(gòu)之堆棧(Stack),結(jié)合實(shí)例形式較為詳細(xì)的分析了堆棧的原理與C#實(shí)現(xiàn)堆棧功能的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-11-11
  • Unity3D開(kāi)發(fā)之獲取所有的子對(duì)象的方法詳解

    Unity3D開(kāi)發(fā)之獲取所有的子對(duì)象的方法詳解

    這篇文章主要為大家詳細(xì)介紹了三種Unity3D中獲取所有的子對(duì)象(child)的方法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-01-01
  • C#中DataTable和List互轉(zhuǎn)的示例代碼

    C#中DataTable和List互轉(zhuǎn)的示例代碼

    很多場(chǎng)景下,我們需要將List轉(zhuǎn)換成為DataTable,本文主要介紹了C#中DataTable和List互轉(zhuǎn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • C#模擬MSN窗體抖動(dòng)的實(shí)現(xiàn)代碼

    C#模擬MSN窗體抖動(dòng)的實(shí)現(xiàn)代碼

    這篇文章主要介紹了C#模擬MSN窗體抖動(dòng)的實(shí)現(xiàn)代碼,非常實(shí)用的一個(gè)功能,需要的朋友可以參考下
    2014-08-08
  • c#異步操作后臺(tái)運(yùn)行(backgroundworker類)示例

    c#異步操作后臺(tái)運(yùn)行(backgroundworker類)示例

    這篇文章主要介紹了c#異步操作后臺(tái)運(yùn)行(backgroundworker類)示例,需要的朋友可以參考下
    2014-04-04
  • c#多線程之線程基礎(chǔ)

    c#多線程之線程基礎(chǔ)

    本文詳細(xì)講解了c#多線程之線程基礎(chǔ),文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-04-04
  • 在C#中向PDF文件添加圖層的詳細(xì)步驟

    在C#中向PDF文件添加圖層的詳細(xì)步驟

    PDF 圖層,能夠讓文檔內(nèi)容按需顯示或隱藏,極大地提升了文檔的靈活性和交互性,而今天,我將帶你一步步探索,如何利用 C# 和一款高效的第三方庫(kù) Spire.PDF,輕松實(shí)現(xiàn) PDF 圖層的創(chuàng)建與管理,需要的朋友可以參考下
    2025-09-09
  • C# 線程安全詳解

    C# 線程安全詳解

    這篇文章主要介紹了c# 線程安全的用法原理及使用示例,幫助大家更好的理解和使用c#,感興趣的朋友可以了解下,希望能夠給你帶來(lái)幫助
    2021-09-09
  • C# winfrom實(shí)現(xiàn)讀取修改xml

    C# winfrom實(shí)現(xiàn)讀取修改xml

    這篇文章主要為大家詳細(xì)介紹了C# winfrom實(shí)現(xiàn)讀取修改xml的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-05-05

最新評(píng)論

武宣县| 宣化县| 新野县| 平舆县| 余姚市| 丹棱县| 自治县| 永登县| 建宁县| 苏尼特左旗| 若羌县| 太原市| 思南县| 沂水县| 明溪县| 荔波县| 惠水县| 会东县| 霍邱县| 海盐县| 涟源市| 子洲县| 孟村| 封开县| 东丰县| 会泽县| 化州市| 青田县| 宁安市| 灵山县| 合作市| 新邵县| 东丽区| 登封市| 黑水县| 青海省| 长岛县| 屏山县| 杭锦后旗| 灌云县| 东宁县|