home commit with new plugins

This commit is contained in:
2026-06-21 09:51:55 +08:00
parent ebb9e385c5
commit 3d067fe75c
85 changed files with 10794 additions and 1443 deletions
+380
View File
@@ -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>();
```