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 類型,則該變數只能儲存整數,不能儲存字串 / 小數之類的資料。




留言

這個網誌中的熱門文章

何謂淨重(Net Weight)、皮重(Tare Weight)與毛重(Gross Weight)

(2021年度)駕訓學科筆試準備題庫歸納分析_法規是非題

Architecture(架構) 和 Framework(框架) 有何不同?_軟體設計前的事前規劃的藍圖概念