DAY 4
5
Software Development

## 嘗試的第一步

``````int[] integers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

Console.WriteLine(\$"Is Array: {integers is Array}"); //Is Array: true

foreach (int integer in integers)
{
Console.Write(\$"{integer} ");
} // 1 2 3 4 5 6 7 8 9
``````

``````Console.WriteLine(\$"Is Array: {integerArray is Array}"); //Is Array: true
``````

``````String integers = "123456789";

Console.WriteLine(\$"Is Array: {integers is Array}"); //Is Array: false

foreach (char integer in integers)
{
Console.Write(\$"{integer} ");
} // 1 2 3 4 5 6 7 8 9
``````

`integers``int[]`改為`String`照樣還是可以做巡覽，這是為什麼呢?

## 從錯誤中學習

``````int integers = 123456789;

foreach (int integer in integers)	//error
{
Console.Write(\$"{integer} ");
}
``````

YA!! 發生錯誤: because 'int' does not contain a public definition for 'GetEnumerator' ，找到關鍵字，原來是沒有定義`GetEnumerator`，那我們就來加上定義:

``````public class IntegerEnum
{

}

public class Integers
{
private int _integers;

public Integers(int integers)
{
_integers = integers;
}

public IntegerEnum GetEnumerator()
{
return new IntegerEnum();
}
}
``````

``````//int integers = 123456789;
Integers integers = new Integers(123456789);
``````

``````public class IntegerEnum
{
private int _integers;
private int _index;
private int _maxDigit;
public int Current { get; private set; }

public IntegerEnum(int integers)
{
_integers = integers;
_index = 0;
_maxDigit = (int)Math.Log10(integers);
}

public bool MoveNext()
{
if (_maxDigit < _index) return false;

Current = getCurrent();
_index++;

return true;
}

private int getCurrent()
{
int currentDigit = _maxDigit - _index;
int result = (_integers / (int)Math.Pow(10, currentDigit)) % 10;  //Get first digit

return result;
}
}

public class Integers
{
private int _integers;

public Integers(int integers)
{
_integers = integers;
}

public IntegerEnum GetEnumerator()
{
return new IntegerEnum(_integers);
}
}
``````

## 原理

### Iterator Pattern

`foreach`的實作是`Iterator Pattern`，下圖為UML圖:

• ConcreteAggregate: `Integers`
• Iterator(): `GetEnumerator()`
• ConcreteIterator: `IntegerEnum`
• next(): 傳回下一個元素，在C#中是以`Current`來抓出目前元素
• hasNext(): 確認是否有下一個元素，在C#中是由`MoveNext()`做確認

`Iterator`裡有個跟C#上的實作差異:

• `Ierator Pattern`上是用`hasNext()`判斷是否有下一個元素，確定有了再Call `Next()`取得元素並更新`index`
• c#裡是用`MoveNext()`判斷是否有下一個元素，確定有了之後去更新`Current``index`

## IEnumerable and IEnumerator

• Aggregate: IEnumerable(ConcreteAggregate的介面)
• Iterator: IEnumerator(ConcreteIterator的介面)

``````public class IntegerEnum : IEnumerator
{
...

public object Current { get; private set; }

public bool MoveNext()
{
if (_maxDigit < _index) return false;

Current = getCurrent();
_index++;

return true;
}

public void Reset()
{
_index = 0;
}

...
}

public class Integers : IEnumerable
{
...

public IEnumerator GetEnumerator()
{
return new IntegerEnum(_integers);
}
}
``````

## 運作

``````foreach (V v in x) embedded_statement
``````

``````{
E e = ((C)(x)).GetEnumerator();
try {
while (e.MoveNext()) {
V v = (V)(T)e.Current;
embedded_statement
}
}
finally {
... // Dispose e
}
}
``````

• V: `int`
• v: `integer`
• x: `integers`
• embedded_statement: `Console.Write(\$"{integer} ");`
• C: Collection Type: `Integers`
• E: Enumerator Type: `IntegerEnum`
• T: element Type: `Integer`

GitHub

## 參考

### 1 則留言

0
morningfungame
iT邦新手 5 級 ‧ 2018-09-28 19:35:09