System.Collections常用集合使用範例

System.Collections應該是所有程式設計師最常使用的namespace了吧,對我來說,常常是心之所至想到什麼就寫什麼,反正可以用就好了。不幸的是上次踩到了一個執行期的地雷(在具備Hash Index的集合中,加入重複的鍵值),所以只好把所知道的集合整了一下,提醒自己以後不要再犯這種陽春等級的錯誤。

程式碼如下所示,哪些可以重複鍵值(非雜湊集合),哪些不可以重複鍵值(雜湊集合),請務必自己要搞清楚喔!

static void Main(string[] args)
{
	//////////
	//非雜湊集合
	//////////

	System.Collections.ArrayList oAL = new System.Collections.ArrayList();
	oAL.Add("John");
	oAL.Add("John");  //OK

	System.Collections.Generic.List<string> oIL = new System.Collections.Generic.List<string>();
	oIL.Add("John");
	oIL.Add("John");  //OK

	System.Collections.Generic.IEnumerable<string> oIE = new string[] { "John", "John" };

	//////////
	//雜湊集合
	//////////

	System.Collections.Hashtable oHT = new System.Collections.Hashtable();
	oHT.Add("John", "1234");
	//oHT.Add("John", "1234");  //Error
	foreach (System.Collections.DictionaryEntry oItem in oHT)
	{
		WriteLine($"Hashtable | key:{oItem.Key.ToString()}, value:{oItem.Value.ToString()}");
	}

	System.Collections.Generic.Dictionary<string, string> oDI = new System.Collections.Generic.Dictionary<string, string>();
	oDI.Add("John", "1234");
	//oDI.Add("John", "1234");   //Error
	foreach (System.Collections.Generic.KeyValuePair<string, string> oItem in oDI)
	{
		WriteLine($"Dictionary | key:{oItem.Key.ToString()}, value:{oItem.Value.ToString()}");
	}
}

在兩個雜湊集合(Hashtable、Dictionary)中,我加入了foreach的寫法將其讀出,可能會有人認為幹嘛寫成這麼複雜,用var動態型別不就好了?我會這樣寫的原因,是因為要提醒我自己這邊的子屬類別是什麼,純粹是「多知道一件事就少犯下一件錯」。而一般來說,Hashtable、Dictionary不太有人會進行foreach的操作,因為類別中提供的ContainsKey、ContainsValue等方法成員就已經很好用了。

至於IEnumerable是所有泛型集合的根源,它實質上只是一個指標指往欲存取的目標實體(instance)而已,我通常用佐以yield return,來解決陣列型別無法動態的新增資料的問題。範例程式碼如下:

利用IEnumerable讓傳統的物件陣列,也可以動態的新增資料

public class Person
{
	public string cName { set; get; }
}

class Program
{
	static void Main(string[] args)
	{
		Person[] oPers = new Person[]
		{
			new Person() { cName = "123" },
			new Person() { cName = "456" }
		};

		System.Collections.Generic.IEnumerable<Person> oTemp;
		oTemp = AddPerson(oPers, new Person() { cName = "789" });
		oTemp = AddPerson(oTemp, new Person() { cName = "012" });

		foreach (var item in oTemp)
		{
			WriteLine(item.cName);
		}
	}

	static System.Collections.Generic.IEnumerable<Person> AddPerson(System.Collections.Generic.IEnumerable<Person> oSource, Person oTarget)
	{
		foreach (Person item in oSource)	{	yield return item; }
		yield return oTarget;
	}
}

執行結果當然就是:

123
456
789
012

補充說明:

1.對IEnumerable有興趣的人,可以參考我的另外一篇文章: 利用yield return與IEnumerable(T)來讓ORM類別可以被集合化與尋訪

2.對System.Collections.Specialized有興趣的人,可以參考我的另外一篇文章: 利用.NET Collections類別來幫你達成Group的功能

3.另有一篇MS MVP Huan-Lin以其他的的面向去整理的集合類型,同樣非常具有參考價值: 選擇合適的 .NET 集合類型

System.Collections ArrayList List IList IEnumerable Hashtable DictionaryEntry Dictionary IDictionary KeyValuePair