C#泛型學習筆記
微軟最先是在 .NET Framework 2.0 中加入了泛型,隨著 .NET Framework 版本的升級,微軟也將之前的非泛型類提供了泛型版本。
而在 .NET Core 中,微軟直接將泛型從 .NET Framework 移植過來,且進行了內部優化,使效能更加優秀。比方:Stack。在.net core中,甚至提供了有Stack的泛型類 Stack<T>
C# 中的泛型有如下優點:
(1) 效能好。=>不存在裝箱和拆箱操作。
在 .NET 資料型別中,有值型別和參考型別之分,值型別的值存在記憶體的堆疊上,參考型別的值存在記憶體的堆上,所以值型別和參考型別在相互轉換時是有效能損失的。
(2) 型別是安全的。
(3) 程式碼重用度高。
定義一個Lesson.cs 的類別,增加以下兩個方法
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DemoCourse { internal class Lesson { public void Show(string s) { Console.WriteLine(s); } public void View<T>(T t) { Console.WriteLine(t); } } }
先不用管 View<T>(T t) 泛型方法是如何定義的,我們只看 Show() 方法與 View<T>() 方法在使用上有什麼區別。現在我們在 Program.cs 中呼叫一下這兩個方法。
Program.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DemoCourse { /// <summary> /// 主程式 /// </summary> internal class Program { static void Main(string[] args) { Lesson lesson = new Lesson(); lesson.Show("數學"); lesson.View<int>(108); lesson.View<string>("經濟學"); lesson.View<double>(8.59); lesson.View<bool>(true); } } }
- Show() 方法定義的是 string 類型的參數,那麼在呼叫時,也只能將 string 類型的值傳入方法。
- View() 方法是泛型方法,參數不是具體的類型,而是 T,T 表示任意一種類型,也稱為類型參數,類型可以在呼叫方法時指定,如 <int> 表示必須使用 int 類型的值傳入方法,而如果<string> 則表示必須使用 string 類型的值傳入。
泛型性能真的比較好嗎?
以ArrayList跟List<T>泛型集合作案例比較
ArrayList 是微軟定義的非泛型類,該類有一個 Add() 方法。
Add() 方法具有一個參數,類型是 object。
object 類型是所有類型的基類,所以對於 Add() 方法,可以接受任意類型的資料。
這邊可以在Program.cs主程式嘗試將
string / int / bool / double 等類型的值作為參數傳入 Add() 方法,這是因為存在一種隱式的轉換:
using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DemoCourse { /// <summary> /// 主程式 /// </summary> internal class Program { static void Main(string[] args) { ArrayList arrayList = new ArrayList(); //隱式轉換(裝箱) arrayList.Add("Kevin"); arrayList.Add(25); arrayList.Add(true); arrayList.Add(9.87); //拆箱(還原回原先對應型態) string a1 = (string)arrayList[0]; int a2 = (int)arrayList[1]; bool a3 = (bool)arrayList[2]; double a4 = (double)arrayList[3]; } } }
在 C# 中,int / bool / double 都是值類型,而 object 是參考類型,存在將值類型轉換為參考類型的過程,稱為裝箱,只要是裝箱操作,都有效能損失。
- arrayList.Add("Kevin");; 是先將 string 類型隱式轉換為 object,然後再執行 Add() 方法。
- arrayList.Add(25); 是先將 int 類型隱式轉換為 object,然後再執行 Add() 方法。
- arrayList.Add(true); 是先將 bool 類型隱式轉換為 object,然後再執行 Add() 方法。
- arrayList.Add(9.87); 是先將 double 類型隱式轉換為 object,然後再執行 Add() 方法。
- 如果我們將 arrayList 中的資料取出來,需要還原為原來的類型,則又存在拆箱操作。
而如果使用泛型列表 List<T> 來儲存資料,就不會存在裝箱和拆箱操作,進而也就不會有效能損失。以下是List<T>示範:
using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DemoCourse { /// <summary> /// 主程式 /// </summary> internal class Program { static void Main(string[] args) { List<int> intList = new List<int>(); //添加,無装箱操作。 intList.Add(100); intList.Add(200); intList.Add(300); //獲取,無拆箱操作。 int int1 = intList[0]; int int2 = intList[1]; int int3 = intList[2]; List<string> stringList = new List<string>(); //添加。 stringList.Add("Simon"); stringList.Add("Nick"); //獲取。 string str1 = stringList[0]; string str2 = stringList[1]; } } }
可見,在使用 List<T> 時,無論是在效能上,還是在型別安全性上,List<T> 都要優於 ArrayList。
型別安全性議題,眾所知周C# 語言是講究強型別的,可以簡單地理解為在某個集合中,只能儲存同一種類型的資料,比如現實生活中的蘋果園,規定該蘋果園只能種蘋果樹,不能種別的樹。
包括 C# 中的變數,也是強型別的,當變數定義時使用 int 類型,則該變數只能儲存整數,不能儲存字串 / 小數之類的資料。
留言
張貼留言