C#泛型應用心得淺析
我們在編寫C#程序的時候,經常遇到兩個模塊的功能非常相似,只是一個是處理int類型,另一個是處理string類型,或者是其他自定義的數據類型,但我們沒有其他的解決方案,只能各自寫多個方法處理每個數據類型,因為方法的參數類型不同。那么是否有一個辦法,在方法中傳入通用的數據類型,這樣就可以合并代碼了。C#泛型應用正是為解決這個問題的。C#泛型應用可以解決什么樣的問題呢?我們先看下面的代碼,代碼中省略了一些內容,但功能是實現一個棧,這個棧只能處理int數據類型:
- public class Stack
- {
- private int[] m_item;
- public int pop() {}
- public void push(int item) {}
- public Stack(int i) {this.m_item = new int[i]; }
- }
上面的代碼運行得很好,但是,如果我們需要一個棧來保存string類型的數據時呢?或許很多人都會想到把上面的代碼copy一份,把int改成string就可以了。當然,這樣做,是沒問題的,但是如果以后需要long,Node類型的棧該怎么辦?繼續復制?這里有種折衷的辦法,是使用一個通用的數據類型object來實現這個棧:
- public class Stack
- {
- private object[] m_item;
- public object pop() {}
- public void push() {}
- public Stack(int o){this.m_item = new object [o]}
- }
雖然這個棧很靈活,可以接收任何數據類型。但全面地說,也不是沒有缺陷的,主要表現在:
◆當Stack處理值類型時,會出現裝箱,拆箱操作,這將在托管堆上分配和回收大量的變量,若數據量大,則性能損失非常嚴重。
◆在處理引用類型時,雖然沒有裝箱和拆箱操作,但將用到數據類型的強制轉換操作,增加了處理器的負擔。
在數據類型的強制轉換上還有更嚴重的問題,如下:
- Node1 x = new Node1();
- stack.push(x);
- Node2 y = (Node2)stack.pop();
上面的代碼在編譯時是沒有問題的,但是由于push了一個Node1類型的數據,但在pop時卻要求轉換為Node2類型,這將出現程序運行時的類型轉換異常,但卻逃離了編譯器的檢查。
針對object類型棧的問題,我們引入泛型,他可以很優雅地解決這些問題。泛型用一個通過的數據類型T來代替object,在類實例化時指定T的類型,運行時(Runtime)自動編譯為本地代碼,運行效率和代碼質量都有很大的提高,并且保證數據類型安全。
C# 泛型應用實例:
下面是使用泛型來重寫上面的棧,用一個通用的數據類型T來作為一個占位符,等待在實例化時用一個實際的類型來替換。如下:
- public class Stack﹤T﹥
- {
- private T[] m_item;
- public T pop() {}
- public void push(T item) {}
- public Stack(int i)
- {
- this.m_item = new T[i];
- }
- }
類的寫法不變,只是引入了通用數據類型T就可以適用于任何數據類型,并且類型安全的。這個類的調用方法:
- Stack﹤int﹥ a = new Stack﹤int﹥(100);
- a.push(10);
- a.push("10"); //這里編譯不通過,因為類a只接收int類型的數據
- int x = a.pop();
- Stack﹤string﹥ b = new Stack﹤string﹥(100);
- b.push(10); //這里編譯不通過,因為類b只接收string類型的數據庫
- b.push("10");
- string y = b.pop();
這個類和object實現的類有截然不同的區別:
1. 他是類型安全的。實例化了int類型的棧,就不能處理string類型的數據,其他數據類型也一樣;
2. 無需裝箱和拆箱。這個類在實例化時,按照鎖傳入的數據類型生成本地代碼,本地代碼數據類型已確定,所以無需裝箱和拆箱。
3. 無需數據類型轉換。
C# 泛型應用心得的一些總結就向你介紹到這里,希望對你了解和學習C# 泛型有所幫助。
【編輯推薦】