Behind The scenes of the C # yield keyword

Source: Internet
Author: User
Tags reflector

https://startbigthinksmall.wordpress.com/2008/06/09/behind-the-scenes-of-the-c-yield-keyword/

Behind The scenes of the C # yield keyword

June 9, by Lars Corneliussen

After reading the great article about the code-saving yield keyword "Give-to-the-yield keyword" by Shay Friedman I tho Ught It could is interesting to know how the yield keyword works behind the scenes.

... it doesn ' t really end the method ' s execution. Yield return pauses the method execution and the next time you call it (for the next enumeration value), the method would C Ontinue to execute from the last yield return call. It sounds a bit confusing I think ... (SHAYF)

By using yield return within a method, returns IEnumerable or IEnumeratorThe language feature is Act Ivated.

Note: IEnumerable is kind of a stateless factory for enumerators. Ienumerable.getenumerator () is a thread safe and can be called multiple times, while the returned stateful Enumerat Or is just a helper for enumerating contained values once. By contract IEnumerator offers a Reset () method, but many implementations just throw a notsupportedexception< /c7>.

Lets Create a enumerator method that yields Some fibonacci nubmers.

 public  class   yieldingclass{ public  ienumerable<< Span style= "COLOR: #0000ff" >int  > Getfibonachisequence () { yield  return  1         ;  yield  return  2         ;  yield  return  3         ;  yield  return  5     ; }}

Note: Yield is not a feature of the. Net Runtime. It is just a C # language feature which gets compiled into simple IL code by the C # compiler.

The compiler now generates a inner class with following signature (Reflector + some renaming):

[compilergenerated]Private Sealed classyieldingenumerator:ienumerable<Object, ienumerator<Object>{    // Fields    Private intState ; Private intCurrent ;  PublicYieldingclass owner; Private intInitialthreadid; //Methods[Debuggerhidden] PublicYieldingenumerator (intState ); Private BOOLMoveNext ();    [Debuggerhidden] IEnumerator<int> ienumerable<int>.    GetEnumerator ();    [Debuggerhidden]    IEnumerator Ienumerable.getenumerator (); [Debuggerhidden]voidIenumerator.reset (); voidIDisposable.Dispose (); //Properties    Objectienumerator<Object>. Current {[Debuggerhidden]Get; } Objectienumerator.current {[Debuggerhidden]Get; }}

the original Method getfibonachisequence () only returns a new instance of the Yieldingenumerator, passing the initial State–2 as well as itself as the owner.

Each enumerator holds a State indicating:

    • -2: Initialized as Enumerable. (not yet an enumerator)
    • -1: Closed
    • 0: Initialized as enumerator.
      If A new enumerator is requested on the same instance, GetEnumerator () returns another new instance of Yieldingenumerator.
    • 1-n: Index of the yield return in the original Getfibonachisequence () method. In case of nested enumerators or other more complex scenarios one yield return consumes more than one index.

The content of Getfibonachisequence () is translated into Yieldingenumerator.movenext ().

In We very simple scenario the code looks like this:

BOOLMoveNext () {Switch(state) { Case 0: State= -1; Current=1; State=1; return true;  Case 1: State= -1; Current=2; State=2; return true;  Case 2: State= -1; Current=3; State=3; return true;  Case 3: State= -1; Current=5; State=4; return true;  Case 4: State= -1;  Break; }    return false;}

Quite easy, isn ' t it?

So far we easily could has created the classes and methods used to enable the yield keyword ourselves, too.

Complex scenarios Microsoft does some tricks, which won ' t compile as c#–at least not how Reflector translate s the resulting IL code.

Lets has a look at some code with a nested enumeration ...

foreach (intin newint[] {12358}) {     yield return i;}

This compiles into:
private bool MoveNext () {    try    {        switch (state)        {case            0: state                =-1;                state = 1;                This.values = new int[] {1, 2, 3, 5, 8};                this.currentpositioninvalues = 0;                while (This.currentpositioninvalues < this.values.Length)                {                    current_i = this.values[ This.currentpositioninvalues];                    current = Current_i;                    state = 2;                    return true;                label_007f: state                    = 1;                    this.currentpositioninvalues++;                }                This. Finally2 ();                break;            Case 2:                goto label_007f;        }        return false;    }    Fault    {this        . System.IDisposable.Dispose ();    }} [/sourcecode]

Now the states 1 and 2 were used to indicate whether the enumerator actually was at some point (2), or wether it was trying t O Retrieve the next value (1).

Things would not compile:

    • goto label_007f is used-to-jump-to-the-iteration over- int[] values. The C # goto statement is not a able to jump into another statements context. But the IL is totally valid as a while the statement in MSIL are nothing but some gotos either.
    • The fault is proper MSIL, and not supported in C #. Basically it acts as a finally which just is executed in case of an error.

Attention: As in anonymous delegates, parameters as well as local and instance variables is passed to the Yieldingenumerator Ce. Read this great post to this:variable scoping in Anonymous Delegates in C #

Thanks for your attention!

Behind The scenes of the C # yield keyword (rpm)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.