泛型#
泛型 = 广泛的类型,用于传递类型参数,让代码可以适配多种数据类型而不丢失类型安全。泛型集合见 集合与泛型。
1. 泛型方法#
在方法名后加 <T>,T 就是类型形参,调用时根据实参自动推导。
// 单类型泛型
public static T Fn<T>(T a)
{
return a;
}
// 多类型泛型
public static dynamic Sum<T1, T2>(T1 a, T2 b)
{
// dynamic 动态类型:不在编译阶段校验,运行时校验
dynamic sum = (dynamic)a + b;
return sum;
}
// 泛型数组打印
public static void WritArr<T>(T[] arr)
{
string str = "[";
for (int i = 0; i < arr.Length; i++)
{
str += i == arr.Length - 1 ? $"{arr[i]}]" : $"{arr[i]},";
}
Console.WriteLine(str);
}
// 泛型 + params
public static void Fn3<T>(params T[] arr) { }
// 泛型 + ref
public static void Fn4<T>(ref T[] arr) { }
调用示例:
Console.WriteLine(Sum(13, 123)); // → 136(自动推导 T1=int, T2=int)
Fn(10); // T = int
Fn("abc"); // T = string
Fn(list); // T = List<string>
2. 泛型类#
// 给类添加泛型 — TTest1, TTest2 是类型形参
class People<TTest1, TTest2>
{
public TTest1 A { get; set; }
public TTest2 B { get; set; }
}
// 实例化时指定具体类型
People<int, string> p = new People<int, string>();
p.A = 1;
p.B = "hello";
3. 泛型接口#
interface IBook<T>
{
T A { get; set; }
T B { get; set; }
}
// 实现时指定 T = int
class Book : IBook<int>
{
public int A { get; set; }
public int B { get; set; }
}
// 实现时指定 T = string
class Book2 : IBook<string>
{
public string A { get; set; }
public string B { get; set; }
}
4. 泛型约束#
使用 where 关键字限制泛型的范围,让泛型"不那么广泛":
class Test
{
// where T : struct → T 只能是值类型
public void Fn1<T>(T v) where T : struct { }
// where T : class → T 只能是引用类型
public void Fn2<T>(T v) where T : class { }
// where T : People → T 只能是 People 的派生类
public void Fn3<T>(T v) where T : People { }
// where T : IPeople → T 只能是实现了 IPeople 接口的类
public void Fn4<T>(T v) where T : IPeople { }
}
约束类型速查表#
| 约束 | 说明 | 示例 |
|---|---|---|
where T : struct |
T 必须是值类型 | int、float、bool |
where T : class |
T 必须是引用类型 | string、object、自定义类 |
where T : ClassName |
T 必须是该类或其派生类 | where T : People |
where T : InterfaceName |
T 必须实现该接口 | where T : IPeople |
where T : new() |
T 必须有无参构造函数 | where T : new() |
使用示例:
Test test = new Test();
test.Fn1(123); // ✅ int 是值类型
// test.Fn1("abc"); // ❌ string 是引用类型
test.Fn2(new People()); // ✅ People 是引用类型
test.Fn3(new People()); // ✅ People 满足 where T : People
test.Fn3(new Student()); // ✅ Student 继承了 People
// test.Fn3(new Book()); // ❌ Book 不是 People 的派生类
test.Fn4(new People()); // ✅ People 实现了 IPeople
test.Fn4(new Student()); // ✅ Student 继承了 People(间接实现 IPeople)
作业:自定义 MyList\<T>#
老师演示版(简洁版)#
class MyList<T>
{
private T[] Arr = new T[0];
// 添加元素(每次创建新数组 +1 长度)
public void Add(T item)
{
T[] values = new T[Arr.Length + 1];
values[Arr.Length] = item;
Arr = values;
}
// 索引器
public T this[int index]
{
get { return Arr[index]; }
set { Arr[index] = value; }
}
// 元素个数
public int Count()
{
return Arr.Length;
}
}
学生实现版(功能更丰富)#
class Mylist<T>
{
T[] Values = new T[2]; // 初始容量 2
private int count;
public int Count { get { return count; } }
// 添加元素(容量不足时自动扩容 ×2)
public void Add(T a)
{
if (count < Values.Length)
{
Values[count++] = a;
}
else
{
T[] val = new T[Values.Length * 2]; // 扩容到 2 倍
Array.Copy(Values, val, Values.Length);
Values = val;
Values[count++] = a;
}
}
// 索引器(带越界检查)
public T this[int index]
{
get
{
if (index < Count && index >= 0)
return Values[index];
throw new Exception("未知索引");
}
set
{
if (index < Count && index >= 0)
Values[index] = value;
else
throw new Exception("未知索引");
}
}
// Find — 用 Func<T, bool> 委托查找
public T Find(Func<T, bool> a)
{
for (int i = 0; i < Count; i++)
{
if (a(Values[i])) return Values[i];
}
return default(T);
}
}
使用:
Mylist<int> mylist = new Mylist<int>();
mylist.Add(123);
mylist.Add(456);
mylist.Add(789);
Console.WriteLine(mylist[2]); // → 789
mylist.Find(i => i < 4); // 使用 Lambda 作为查找条件
相关笔记#
- 集合与泛型 — 集合基础与 Action 委托
- 委托与 Lambda — 泛型委托 MyDelegate\<T>
- Array 数组方法 — 泛型 Find 系列(0730 作业)
- 索引器 — 索引器(MyList 中 this[int] 的实现)