Home [C# 筆記] 泛型
Post
Cancel

[C# 筆記] 泛型

泛型

  • 概念:使用佔位符T來代表某種類型,編譯期間決定其具體類型

  • 格式:

1
class MyGeneric<T>
  • 使用:
1
MyGeneric<int> mg = new MyGeneric<int>();
  • 原理:編譯器在編譯的時候,會使用特化的類型替代掉類型佔位符,生成具體的class程式碼。

需求

  • 請設計儲存倉庫類:class Store,要求其可以儲存intfloat或者double數據。

只有數據類型不同,但邏輯相同

改造前

1
2
3
4
5
6
7
8
class Store
{
    private int[] arr = new int[100];
    public void Put(int v, int index)
    {
        arr[index] = v;
    }
}

改造為泛型

第一步:類別加上佔位符

  • T是類型佔位符,表示還沒有決定具什麼類型,先把這個位置佔著。
1
2
3
4
5
6
7
8
class Store<T>
{
    private T[] arr = new T[100];
    public void Put(T v, int index)
    {
        arr[index] = v;
    }
}
  • 佔位符不一定非得用T,也可以用其他的字符或者名字。
1
2
3
4
5
6
7
8
class Store<MyT>
{
    private MyT[] arr = new MyT[100];
    public void Put(MyT v, int index)
    {
        arr[index] = v;
    }
}

具體使用

1
2
3
4
5
6
static void Main(string[] args)
{
    //對泛型類Store的特化,特化為int類型的類別
    Store<int> store = new Store<int>();
    Store<float> store2 = new Store<float>();
}

泛型

  • 通過「參數化類型」,實現在同一份程式碼上操作多種數據類型
  • 泛型可以修飾:類別、方法、委託等。

泛型方法格式

1.交換兩個變量的值

改造前

1
2
3
4
5
public static void Swap(int a, int b) {
    int temp = a;
    a = b;
    b = temp;
}
  • ref代表的是,傳進來的是這兩個變數的引用,調用Swap()方法,外面傳進來的實參也會被同時修改。
  • 也就是說,如果想要在Swap()方法裡面去影響傳進來的實參它本身的值,就加上一個ref

改造成泛型

  • 在方法的名字後面加上一個泛型的<T>
  • 加上後,我們可以用這個T類型,也就是說這個類型佔位符去替換int
  • 變量temp的類型也要替換成T類型
1
2
3
4
5
6
public static void Swap<T>(ref T a, ref T b)
{
    T temp = a;
    a = b;
    b = temp;
}

泛型方法的使用

1
2
3
4
5
6
static void Main(string[] args)
{
    //泛型方法的使用
    int x = 10, y = 20;
    Swap<int>(ref x, ref y);
}

2.求兩個變量的加和

改造前

1
2
3
public static int Add(int a, int b) {
    return a + b;
}

改造成泛型

因為「運算子+不可套用至類型為TT的運算元」,所以使用dynamic

1
2
3
4
5
public static T Add<T>(T a, T b) {
    dynamic aa = a;
    dynamic bb = b;
    return aa + bb;
}

泛型方法的使用

1
2
3
4
5
static void Main(string[] args)
{
    Add<int>(10, 20);
    Add<float>(1.1f, 2.2f);
}

如果傳進來的變量,是不能夠被相加,運行時會直接報錯。例如傳進來兩個 cat物件

1
2
3
4
5
6
7
static void Main(string[] args)
{
    //兩個cat是不能做加和,會報錯
    Cat cat1 = new Cat();
    Cat cat2 = new Cat();
    Add<Cat>(cat1, cat2);
}

泛型細節

  • 多類型佔位符:泛型可以同時提供多種數據類型的佔位符(類別/方法均有效)
1
2
3
4
5
class Store<T, U>
{
    public T[] Arr1 = new T[100];
    public U[] Arr2 = new U[100];
}
  • 泛型繼承:泛型類可以被繼承,子類可以指定父類泛型的具體類型(特化)或者子類也作為泛型類
  1. 指定父類泛型的具體類型(特化)
1
2
class Person<T> {...}
class Teacher:Person<int> {...}
  1. 子類也作為泛型類
1
2
class Person<T> {...}
class Teacher<T>:Person<T> {...}

多類型佔位符

泛型可以同時提供多種數據類型的佔位符(類別/方法均有效)

改造前

比如說,Store類別有兩個類型的陣列屬性,第一個是int[]陣列類型,第二個是float[]陣列類型,能不能把它給泛型化呢?

1
2
3
4
5
class Store
{ 
    public int[] Arr1 { get; set; }
    public float[] Arr2 { get; set; }
}

我們一樣在class 後面加上<T>類型,將陣列類型都改成T類型。

但是,因為只有一個類型佔位符T,導致Arr1Arr2必然是同一種數據類型

1
2
3
4
5
6
//因為只有一個類型佔位符T,導致Arr1和Arr2必然是同一種數據類型
class Store<T>
{ 
    public T[] Arr1 { get; set; }
    public T[] Arr2 { get; set; }
}

改造成泛型類別

有沒有一種方法,既能夠讓這兩個陣列是兼容的各式各樣的數據類型呀?又能夠使得他們倆的數據可能會不一樣呢?

我們可以再寫一個佔位符,比如說叫是U,而T是用來規定Arr1的,U是用來規定Arr2

1
2
3
4
5
6
7
//因為只有一個類型佔位符T,導致Arr1和Arr2必然是同一種數據類型
//我們可以再寫一個佔位符,比如說叫是U,而T是用來規定Arr1的,U是用來規定Arr2的
class Store<T,U>
{ 
    public T[] Arr1 { get; set; }
    public U[] Arr2 { get; set; }
}

使用方式

1
2
3
4
5
static void Main(string[] args)
{
    //T = int, U = float
    Store<int, float> store = new Store<int, float>();
}

泛型繼承

泛型類可以被繼承,子類可以指定父類泛型的具體類型(特化)或者子類也作為泛型類

將父類進行特化,然後繼承

子類可以指定父類泛型的具體類型(特化)

1
2
3
4
5
6
//1.將父類進行特化,然後繼承
class Person<T> { 
    public int Id { get; set; }
}
class Teacher : Person<int> { 
}

子類也作為泛型類

一時沒辦法決定到底該繼承怎樣的父類,在特化子類的時候,一把父類特化掉。

1
2
3
4
5
6
//2.無法在class Teacher 子類聲明的時候決定父類的泛型類型
class Person<T> { 
    public int Id { get; set; }
}
class Teacher<T> : Person<T> { 
}

結合以上兩點

  • 多類型佔位符
  • 泛型繼承
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Person<T> { 
    public int Id { get; set; }
}

//Teacher<int, float>
//內涵:int Id, float Date
class Teacher<T,U> : Person<T> { 
    public U Data { get; set; }
}

static void Main(string[] args)
{
    Teacher<int, float> teacher = new Teacher<int, float>();
}

https://www.bilibili.com/video/BV1na4y1g7AA/

This post is licensed under CC BY 4.0 by the author.