利用yield return與IEnumerable(T)來讓ORM類別可以被集合化與尋訪

一般來說,如果我在進行ORM(Object Relational Mapping)類別的輸出,丟到外部要另外進行處理時,我都會調用System.Collections.Generic.List<T>來進行處理。但是List<T>畢竟已經時做過完整的IEnumerable程式碼了,在效能上可能會耗損過多的系統資源,因此我們可以改用IEnumerable<T>來進行處理,對於單純運送物件集合包上面的動作,對記憶體的耗損上可能會有比較高的系統效率。

IEnumerable<T>的使用方式

IEnumerable<T>顧名思義就是一個泛型的介面,用來當作一個集合容器,我們從下方的程式碼中可以發現,當你實作這個泛型介面時,可以將任何的實體塞進去。以下面為例,這是字串陣列IEnumerable<T>化的使用方式。有了IEnumerable<T>化後,我們就可以使用最喜歡的foreach來尋訪它。

static void Main(string[] args)
{
	IEnumerable<string> oTemp = new string[] { "小明", "小華", "小英", "老王" };
	foreach (string obj in oTemp)
	{
		Console.WriteLine(obj);
	}
	Console.WriteLine("--- END ---");
	Console.Read();
}

當然,要塞自訂的物件實體也沒問題。

class emp
{
	public string cName {get; set;}
}
static void Main(string[] args)
{
	IEnumerable<emp> oTemp = new emp[] {
		new emp { cName = "小明" },
		new emp { cName = "小華" },
	};
	foreach (emp obj in oTemp)
	{
		Console.WriteLine(obj.cName);
	}
	Console.WriteLine("--- END ---");
	Console.Read();
}

接下來換yield return出場

現在問題來了,假設你從資料庫讀到了一千筆資料放在DataTable中,我們應該不會想要慢慢new到字串陣列再使其自動轉換成IEnumerable<string>,而這也不是List<T>可以讓我們來Add(Object),這時候我們可以請神(yield return)上身嘍!yield return會幫我們把要輸出的物件一個轉成IEnumerable<T>,並且動態的丟出去。

class Program
{
	static void Main(string[] args)
	{
		foreach (ORMEmployee obj in GetList.Employee())
		{
			Console.WriteLine(obj.cName);
		}
		Console.WriteLine("--- END ---");
		Console.Read();
	}
}
class ORMEmployee
{
	public string cName { get; set; }
}

class GetList
{
	public static IEnumerable<ORMEmployee> Employee()
	{
		//這裡可能取材自資料庫之類的東西
		string[] aryEmployee = new string[] { "小明", "小華", "小英", "老王" };
		foreach (string cTemp in aryEmployee)
		{
			yield return new ORMEmployee() { cName = cTemp };
		}
	}
}

當然啦,沒有List<T>的缺點就是你沒有辦法進行後續的Add()、Remove()等操作,這是大家可能要先有心理準備的事。此外,IEnumerable<T>依然是可以被強大的Json.Net序列化的喔!詳見下列程式碼:

Console.WriteLine(
	Newtonsoft.Json.JsonConvert.SerializeObject(GetList.Employee())
);
System.Collections.IEnumerable(T) System.Collections.Generic(T) YieldReturn YieldBreak