home commit with new plugins
This commit is contained in:
@@ -0,0 +1,380 @@
|
||||
# 泛型
|
||||
|
||||
概念:
|
||||
泛型就是把==类型==参数化,让一份代码可以适配多种数据类型。
|
||||
可以理解为:先把类型空出来,等使用时再指定具体类型。
|
||||
|
||||
例如:
|
||||
```csharp
|
||||
List<int> nums = new List<int>();
|
||||
List<string> names = new List<string>();
|
||||
```
|
||||
|
||||
其中 `int` 和 `string` 就是传入泛型的具体类型。
|
||||
|
||||
----
|
||||
# 为什么需要泛型
|
||||
|
||||
泛型的主要作用:
|
||||
1. 提高代码复用性
|
||||
2. 保证类型安全
|
||||
3. 减少强制类型转换
|
||||
4. 避免不必要的装箱和拆箱
|
||||
|
||||
对比 `ArrayList`:
|
||||
```csharp
|
||||
ArrayList list = new ArrayList();
|
||||
list.Add(1);
|
||||
list.Add("hello");
|
||||
|
||||
int num = (int)list[0];
|
||||
```
|
||||
|
||||
`ArrayList` 内部存的是 `object`,取值时经常需要强制转换。
|
||||
|
||||
使用泛型集合:
|
||||
```csharp
|
||||
List<int> list = new List<int>();
|
||||
list.Add(1);
|
||||
|
||||
int num = list[0];
|
||||
```
|
||||
|
||||
`List<int>` 只能存 `int`,编译器会提前帮我们检查类型错误。
|
||||
|
||||
----
|
||||
# 常见泛型形式
|
||||
|
||||
泛型可以用于:
|
||||
1. 泛型类
|
||||
2. 泛型接口
|
||||
3. 泛型方法
|
||||
4. 泛型委托
|
||||
5. 泛型集合
|
||||
|
||||
常见泛型集合:
|
||||
```csharp
|
||||
List<T>
|
||||
Dictionary<TKey, TValue>
|
||||
Queue<T>
|
||||
Stack<T>
|
||||
HashSet<T>
|
||||
```
|
||||
|
||||
`T`、`TKey`、`TValue` 都是泛型类型参数名。
|
||||
|
||||
----
|
||||
# 语法
|
||||
|
||||
泛型类:
|
||||
```csharp
|
||||
class 类名<T>
|
||||
{
|
||||
}
|
||||
```
|
||||
|
||||
泛型接口:
|
||||
```csharp
|
||||
interface 接口名<T>
|
||||
{
|
||||
}
|
||||
```
|
||||
|
||||
泛型方法:
|
||||
```csharp
|
||||
返回值类型 方法名<T>(T 参数)
|
||||
{
|
||||
}
|
||||
```
|
||||
|
||||
多个泛型类型参数:
|
||||
```csharp
|
||||
class 类名<T1, T2>
|
||||
{
|
||||
}
|
||||
```
|
||||
|
||||
----
|
||||
# 泛型类
|
||||
|
||||
泛型类适合用来保存或处理某种不确定类型的数据。
|
||||
|
||||
```csharp
|
||||
class Box<T>
|
||||
{
|
||||
public T Value { get; set; }
|
||||
|
||||
public Box(T value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public T GetValue()
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
使用:
|
||||
```csharp
|
||||
Box<int> intBox = new Box<int>(10);
|
||||
Console.WriteLine(intBox.GetValue());
|
||||
|
||||
Box<string> stringBox = new Box<string>("hello");
|
||||
Console.WriteLine(stringBox.GetValue());
|
||||
```
|
||||
|
||||
理解:
|
||||
1. `Box<T>` 定义时不知道 `T` 是什么类型
|
||||
2. `Box<int>` 使用时把 `T` 替换成 `int`
|
||||
3. `Box<string>` 使用时把 `T` 替换成 `string`
|
||||
|
||||
----
|
||||
# 泛型接口
|
||||
|
||||
泛型接口常用于规定一类对象必须提供某种泛型能力。
|
||||
|
||||
```csharp
|
||||
interface IRepository<T>
|
||||
{
|
||||
void Add(T item);
|
||||
T Get(int index);
|
||||
}
|
||||
```
|
||||
|
||||
实现:
|
||||
```csharp
|
||||
class MemoryRepository<T> : IRepository<T>
|
||||
{
|
||||
private List<T> items = new List<T>();
|
||||
|
||||
public void Add(T item)
|
||||
{
|
||||
items.Add(item);
|
||||
}
|
||||
|
||||
public T Get(int index)
|
||||
{
|
||||
return items[index];
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
使用:
|
||||
```csharp
|
||||
IRepository<string> repository = new MemoryRepository<string>();
|
||||
|
||||
repository.Add("小明");
|
||||
Console.WriteLine(repository.Get(0));
|
||||
```
|
||||
|
||||
----
|
||||
# 泛型方法
|
||||
|
||||
泛型方法适合处理“逻辑一样,但参数类型不同”的情况。
|
||||
|
||||
```csharp
|
||||
static void Print<T>(T value)
|
||||
{
|
||||
Console.WriteLine(value);
|
||||
}
|
||||
```
|
||||
|
||||
使用:
|
||||
```csharp
|
||||
Print<int>(100);
|
||||
Print<string>("hello");
|
||||
Print<bool>(true);
|
||||
```
|
||||
|
||||
很多时候,编译器可以自动推断泛型类型:
|
||||
```csharp
|
||||
Print(100);
|
||||
Print("hello");
|
||||
Print(true);
|
||||
```
|
||||
|
||||
----
|
||||
# 泛型约束
|
||||
|
||||
默认情况下,泛型类型 `T` 可以是任意类型。
|
||||
|
||||
如果希望限制 `T` 必须满足某些条件,可以使用 `where` 约束。
|
||||
|
||||
语法:
|
||||
```csharp
|
||||
class 类名<T> where T : 约束
|
||||
{
|
||||
}
|
||||
```
|
||||
|
||||
常见约束:
|
||||
|
||||
| 约束 | 含义 |
|
||||
| --- | --- |
|
||||
| `where T : class` | `T` 必须是引用类型 |
|
||||
| `where T : struct` | `T` 必须是值类型 |
|
||||
| `where T : new()` | `T` 必须有无参构造函数 |
|
||||
| `where T : 父类名` | `T` 必须继承某个父类 |
|
||||
| `where T : 接口名` | `T` 必须实现某个接口 |
|
||||
|
||||
案例:
|
||||
```csharp
|
||||
class Factory<T> where T : new()
|
||||
{
|
||||
public T Create()
|
||||
{
|
||||
return new T();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
因为加了 `where T : new()`,所以可以在类中使用 `new T()`。
|
||||
|
||||
----
|
||||
# 多泛型参数
|
||||
|
||||
一个类或方法可以同时使用多个泛型参数。
|
||||
|
||||
```csharp
|
||||
class Pair<TKey, TValue>
|
||||
{
|
||||
public TKey Key { get; set; }
|
||||
public TValue Value { get; set; }
|
||||
|
||||
public Pair(TKey key, TValue value)
|
||||
{
|
||||
Key = key;
|
||||
Value = value;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
使用:
|
||||
```csharp
|
||||
Pair<int, string> pair = new Pair<int, string>(1, "小明");
|
||||
|
||||
Console.WriteLine(pair.Key);
|
||||
Console.WriteLine(pair.Value);
|
||||
```
|
||||
|
||||
----
|
||||
# default 关键字
|
||||
|
||||
泛型中有时不知道 `T` 的默认值是什么,可以使用 `default`。
|
||||
|
||||
```csharp
|
||||
static T GetDefault<T>()
|
||||
{
|
||||
return default(T);
|
||||
}
|
||||
```
|
||||
|
||||
常见默认值:
|
||||
|
||||
| 类型 | 默认值 |
|
||||
| --- | --- |
|
||||
| `int` | `0` |
|
||||
| `bool` | `false` |
|
||||
| 引用类型 | `null` |
|
||||
| 结构体 | 所有字段都是默认值 |
|
||||
|
||||
新语法也可以写成:
|
||||
```csharp
|
||||
return default;
|
||||
```
|
||||
|
||||
----
|
||||
# 完整案例
|
||||
|
||||
```csharp
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace GenericsDemo
|
||||
{
|
||||
internal class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
DataStore<int> intStore = new DataStore<int>();
|
||||
intStore.Add(10);
|
||||
intStore.Add(20);
|
||||
|
||||
Console.WriteLine(intStore.Get(0));
|
||||
Console.WriteLine(intStore.Get(1));
|
||||
|
||||
DataStore<string> stringStore = new DataStore<string>();
|
||||
stringStore.Add("hello");
|
||||
stringStore.Add("world");
|
||||
|
||||
Console.WriteLine(stringStore.Get(0));
|
||||
Console.WriteLine(stringStore.Get(1));
|
||||
|
||||
Print(123);
|
||||
Print("泛型方法");
|
||||
}
|
||||
|
||||
static void Print<T>(T value)
|
||||
{
|
||||
Console.WriteLine(value);
|
||||
}
|
||||
}
|
||||
|
||||
interface IDataStore<T>
|
||||
{
|
||||
void Add(T value);
|
||||
T Get(int index);
|
||||
}
|
||||
|
||||
class DataStore<T> : IDataStore<T>
|
||||
{
|
||||
private List<T> values = new List<T>();
|
||||
|
||||
public void Add(T value)
|
||||
{
|
||||
values.Add(value);
|
||||
}
|
||||
|
||||
public T Get(int index)
|
||||
{
|
||||
return values[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
理解:
|
||||
1. `DataStore<T>` 是泛型类
|
||||
2. `IDataStore<T>` 是泛型接口
|
||||
3. `Print<T>` 是泛型方法
|
||||
4. `DataStore<int>` 只能保存整数
|
||||
5. `DataStore<string>` 只能保存字符串
|
||||
|
||||
----
|
||||
# 注意
|
||||
|
||||
1. 泛型类型参数常用 `T` 表示,但不是固定写法
|
||||
2. 多个泛型参数常写成 `TKey`、`TValue`、`TItem`
|
||||
3. `List<T>` 比 `ArrayList` 更常用,也更安全
|
||||
4. 泛型在编译期就能检查类型错误
|
||||
5. 使用泛型可以减少 `object` 带来的强制转换
|
||||
6. 如果需要在泛型中 `new T()`,必须加 `where T : new()` 约束
|
||||
7. 泛型不是“任何类型都乱放”,而是“使用时确定一种类型”
|
||||
|
||||
----
|
||||
# 小结
|
||||
|
||||
一句话:
|
||||
泛型就是==把类型当作参数传进去==。
|
||||
|
||||
记忆:
|
||||
普通参数控制“值”。
|
||||
泛型参数控制“类型”。
|
||||
|
||||
最常见写法:
|
||||
```csharp
|
||||
List<int> nums = new List<int>();
|
||||
Dictionary<string, int> scores = new Dictionary<string, int>();
|
||||
```
|
||||
Reference in New Issue
Block a user