55. yield return implementation

פעם שעברה, הכרנו את yield return.

הפעם נדבר קצת על איך זה ממומש:

נחזור לדוגמה של הסדרה החשבונית של אתמול:

1
2
3
4
5
6
7
8
9
10
11
public static IEnumerable<int> ArithmeticSequence
(int first, int difference, int count)
{
int currentTerm = first;
for (int i = 1; i <= count; i++)
{
yield return currentTerm;
currentTerm += difference;
}
}

אם נסתכל בReflector עליו נראה איזה IEnumerable שהוא גם IEnumerator מג’ונרט.

בתוכו יש מתודה כזאת:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
private bool MoveNext()
{
switch (this.state)
{
case 0:
this.state = -1;
this.currentTerm = this.first;
this.i = 1;
while (this.i <= this.count)
{
this.current = this.currentTerm;
this.state = 1;
return true;
NotFirstIteration:
this.state = -1;
this.currentTerm += this.difference;
this.i++;
}
break;
case 1:
goto NotFirstIteration;
}
return false;
}

ננסה להסביר מה קורה:

כשיוצרים את הIEnumerable הזה בהתחלה, הוא מאותחל עם state = 0.

כשעושים MoveNext לראשונה הוא נכנס לחלק הראשון בו הוא מאתחל את currentTerm, לfirst ואת i ל1.

אחרי זה הוא נכנס ללולאה וקובע שהcurrent הוא currentTerm והופך את הstate להיות 1, ומחזיר שהMoveNext הצליח.

בפעם הבאה שקוראים לMoveNext, הוא עם state = 1.

הוא משנה את הState להיות -1, מגדיל את currentTerm בdifference, מגדיל את i ב1 וממשיך בלולאה.

כך באופן חוזר חלילה הוא משנה את current להיות currentTerm ומחזיר שהMoveNext הצליח, עד שi מגיע לcount.

כלומר מה שקורה הוא שהאובייקט בעצם שומר את הstate של המתודה שאנחנו נמצאים בה, וכל פעם שאנחנו עושים לו MoveNext הוא קורא למתודה מחדש עם הState שלה.

בסה"כ די מגניב.

שיהיה אחלה סופ"ש בר-מנייה

שתף