這個做法比較像做法 29 的延伸,主軸還是在講 Iterator Methods 但提到了更詳細的好處,還有另一個好處是 可以把多個 Iterator Methods 拼接起來的特性,這個特性在做法後半段會提到。

在做法 29 也有提到使用 yield return 並且回傳值是 IEnumerableIEnumerable<T> 就是一個 Iterator Methods

因為做法 29 的例子比較簡單,這個做法有提出一個現實更常碰到的問題就是集合處理,例如傳入一個 IEnumerable<T> 參數透過我們的寫的方法處理 後回傳一個 IEnumerable<T> 結果,下面這段程式碼會將傳入的集合移除重複的成員最後回傳乾淨的集合。

public static IEnumerable<int> UniqueV1(IEnumerable<int> nums)
{
	var uniqueVals = new HashSet<int>();
	foreach (var num in nums)
	{
		if (!uniqueVals.Contains(num))
		{
		    Console.WriteLine("Adding {0}", num);
			uniqueVals.Add(num);
		}
	}
	return uniqueVals;
}

void Main()
{
	var ll = new List<int>() { 1, 2, 3, 4, 1, 2, 3 };
	foreach (var element in UniqueV1(ll))
	{
		Console.WriteLine(element);
	}
}

Adding 1
Adding 2
Adding 3
Adding 4
1
2
3
4

上面那種寫法可以改寫成使用 yield return 的版本,可以更節省記憶體並運行效率更好。

public static IEnumerable<int> UniqueV2(IEnumerable<int> nums)
{
	var uniqueVals = new HashSet<int>();
	foreach (var num in nums)
	{
		if (!uniqueVals.Contains(num))
		{
		    Console.WriteLine("Adding {0}", num);
			uniqueVals.Add(num);
			yield return num;
		}
	}
}

void Main()
{
	var ll = new List<int>() { 1, 2, 3, 4, 1, 2, 3 };
	foreach (var element in UniqueV2(ll))
	{
		Console.WriteLine(element);
	}
}

Adding 1
1
Adding 2
2
Adding 3
3
Adding 4
4

從輸出可以看出上面兩種寫法執行順序不太一樣,UniqueV1 是將資料全部準備好才進行輸出,UniqueV2 則是準備好一個元素就會先回到 Main 方法 接下來才繼續處理下一個元素,這種運行方式也叫做 Continuable methods

Iterator Methods 的另一個好處是可以將多個 Iterator Methods 結果串聯起來,像下面這個方法會將結果平方之後回傳集合。

public static IEnumerable<int> Square(IEnumerable<int> nums)
{
	foreach (var num in nums)
		yield return num * num;
}

可以使用 Square(UniqueV2(nums) 這種寫法將方法串起來。

void Main()
{
	var nums = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 1, 2, 3 };

	foreach (var num in Square(UniqueV2(nums)))
	{
		Console.WriteLine("Number returned from Unique: {0}", num);
	}
}

Number returned from Unique: 1
Number returned from Unique: 4
Number returned from Unique: 9
Number returned from Unique: 16
Number returned from Unique: 25
Number returned from Unique: 36
Number returned from Unique: 49

Summary

這個做法就是把 Iterator Methods 的特性在詳細的描述一次,並且提到使用這樣的寫法因為輸入輸出的類型都是 IEnumerable<T> 所以 很容易串聯起來,並且閱讀起來也非常易懂。