DAY 5
4
Software Development

## 進化的程式碼

``````private static void outputDivide_for(int maxNum, int divide)
{
for (int currentNum = 1; currentNum <= maxNum; currentNum++)
{
if (currentNum % divide != 0) continue;
Console.Write(\$"{currentNum} ");
}
Console.WriteLine();
}
``````

• 顯示方式要改成每行一個數字:
``````for (int currentNum = 1; currentNum <= maxNum; currentNum++)
{
if (currentNum % divide != 0) continue;
//Console.Write(\$"{currentNum} ");
Console.WriteLine(\$"{currentNum} ");
}
Console.WriteLine();
``````
• 計算邏輯修改成: 在1到特定數字中輸出可以被某數的2倍整除的數列:
``````int divideMultitwo = divide * 2;
for (int currentNum = 1; currentNum <= maxNum; currentNum++)
{
//if (currentNum % divide != 0) continue;
if (currentNum % divideMultitwo != 0) continue;
//Console.Write(\$"{currentNum} ");
Console.WriteLine(\$"{currentNum} ");
}
Console.WriteLine();
``````

``````private static void outputDivide_foreach_List(int maxNum, int divide)
{
foreach (int item in enumerable_List(maxNum, divide))
{
Console.Write(\$"{item} ");
}
Console.WriteLine();
}

private static IEnumerable enumerable_List(int maxNum, int divide)
{
List<int> result = new List<int>();

for (int currentNum = 1; currentNum <= maxNum; currentNum++)
{
if (currentNum % divide != 0) continue;
}
return result;
}
``````

• `outputDivide_for`改成下面這樣，直接`break`
``````private static void outputDivide_for(int maxNum, int divide)
{
for (int currentNum = 1; currentNum <= maxNum; currentNum++)
{
break;
}
}
``````
• `outputDivide_foreach_List`也一樣，直接`break`
``````private static void outputDivide_foreach_List(int maxNum, int divide)
{
foreach (int item in enumerable_List(maxNum, divide))
{
break;
}
}
``````

``````private static IEnumerable enumerable_Iterator(int maxNum, int divide)
{
integersAggregate enumerable = new integersAggregate(maxNum, divide);
return enumerable;
}

private class integersAggregate : IEnumerable
{
private int _maxNum;
private int _divide;

public integersAggregate(int maxNum, int divide)
{
_maxNum = maxNum;
_divide = divide;
}

public IEnumerator GetEnumerator()
{
return new integersInterator(_maxNum, _divide);
}
}
private class integersInterator : IEnumerator
{
private int _maxNum;
private int _divide;
private int currentNum = 1;

public integersInterator(int maxNum, int divide)
{
_maxNum = maxNum;
_divide = divide;
}

public object Current { get; private set; }

public bool MoveNext()
{
do
{
if (currentNum % _divide == 0)
{
Current = currentNum;
return true;
}
currentNum++;
} while (currentNum <= _maxNum);
return false;
}

public void Reset()
{
currentNum = 1;
}
}
``````

`foreach``IEnumerable`搭配，每次都是叫用`MoveNext`來確定是否有下一個元素，如果有則將下一個元素值賦予`Current`變數，所以每次只會取得下一個元素，也不會增加額外的空間消費。

• 可以保證計算的花費一定值得(效能問題解決)
• 可以將巡覽及計算邏輯拆分(可維護性提高)

## yield

``````private static IEnumerable enumerable_yield(int maxNum, int divide)
{
for (int currentNum = 1; currentNum <= maxNum; currentNum++)
{
if (currentNum % divide != 0) continue;
yield return currentNum;
}
}
``````

• 如果一個區塊(block)中有`yield`陳述式，此區塊就叫做Iterator Block
• 一個方法的區塊如果是Iterator Block，則它的回傳值會是`IEnumerable``IEnumerator`

### 運作方式

`foreach`觸發`MoveNext()`時: 可以想成是去執行Iterator Block內的程式碼，執行到`yield return`時它做了三件事情:

• Iterator Block的執行暫停
• `Current`更新成`yield return`的value
• `MoveNext()`回傳true

`foreach`在執行完embedded_statement後再次觸發`MoveNext()`時會從原本暫停的地方再執行下去直到Iterator Block中的程式:

• 再次觸發`yield return`
• 執行結束
• `yield break`

``````private static IEnumerable enumerable_yield2()
{
yield return 1;
yield return 2;
yield return 3;
yield return 4;
yield return 5;
yield return 6;
yield return 7;
yield return 8;
yield return 9;
yield break;
yield return 10;

//1 2 3 4 5 6 7 8 9
}
``````

PS: 本節可以搭配上一篇介紹的`foreach`來做學習，會比較好懂。

GitHub

## 參考

### 3 則留言

0

iT邦大師 1 級 ‧ 2018-03-04 02:22:24

0
ShawnGood
iT邦新手 5 級 ‧ 2018-07-29 17:24:20

0
wayneli
iT邦新手 5 級 ‧ 2019-01-26 17:31:32