跳转至

泛型#

泛型 = 广泛的类型,用于传递类型参数,让代码可以适配多种数据类型而不丢失类型安全。泛型集合见 集合与泛型

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 必须是值类型 intfloatbool
where T : class T 必须是引用类型 stringobject、自定义类
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 作为查找条件

相关笔记#