泛型
1
| MyGeneric<int> mg = new MyGeneric<int>();
|
- 原理:編譯器在編譯的時候,會使用特化的類型替代掉類型佔位符,生成具體的
class程式碼。
需求
- 請設計儲存倉庫類:
class Store,要求其可以儲存int、float或者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;
}
|
改造成泛型
因為「運算子+不可套用至類型為T 和 T的運算元」,所以使用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
2
| class Person<T> {...}
class Teacher:Person<int> {...}
|
- 子類也作為泛型類
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,導致Arr1和Arr2必然是同一種數據類型
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/