C#自学笔记:泛型编程

泛型

概念

泛型实现了类型参数化,达到代码重用目的

通过类型参数化来实现同一份代码上操作多种类型

• 泛型相当于类型占位符

• 定义类或方法时使用替代符代表变量类型

• 当真正使用类或者方法时再具体指定类型

泛型分类

  1. 泛型类和泛型接口

基本语法:

class 类名<泛型占位字母>

interface 接口名<泛型占位字母>

  1. 泛型函数

基本语法:

函数名<泛型占位字母>(参数列表)

注意:泛型占位字母可以有多个,用逗号分开

泛型类和接口

使用
//类
class TestClass<T>
{
    public T value;
}
class TestClass2<T1, T2, K, M, LL, Key, Value>
{
    public T1 value1;
    public T2 value2;
    public K value3;
    public M value4;
    public LL value5;
    public Key value6;
    public Value value7;
}

//使用
TestClass<int> t = new TestClass<int>();
t.value = 10;
TestClass<string> t2 = new TestClass<string>();
t2.value = "123123";

TestClass2<int, string, float, double, TestClass<int>, uint, short> t3 = new TestClass2<int, string, float, double, TestClass<int>, uint, short>();
//接口
interface TestInterface<T>
{
    T value
    {
        get;
        set;
    }
}

class Test :TestInterface<int>
{
    public int value {get => throw new NotImplementedException();
                      set => throw new NotImplementedException(); }
}

泛型方法

使用
//普通类中的泛型方法
class Test2
{
    public void TestFun<T>(T value)
    {
        Console.WriteLine(value);
    }
    public void TestFun<T>()
    {
        T t = defalut(T);
    }
    public T TestFun<T>(string v)
    {
        return default(T);
    }
    public void TestFun<T, K, M>(T t, K k, M m)
    {
    }
}

//使用
Test2 tt = new Test2();
tt.TestFun<string>("123123");

//泛型类中的泛型方法
class Text2<T>
{
    public T value;

    //这个不叫泛型方法,因为T是泛型类声明的时候就指定了
    public void TestFun(T t)
    {
    }
    //这个才是泛型方法
    public void TestFun<K>(K k)
    {
        Console.WriteLine(k);
    }
}

作用

  1. 不同类型对象的相同逻辑处理就可以选择泛型
  2. 使用泛型可以一定程度避免装箱拆箱

举例:优化ArrayList,使用泛型确定对象类型,避免装箱拆箱

泛型约束

让泛型的类型有一定的限制,意思就是这个泛型只能是约束的类型

关键字:where

泛型约束一共有6种

类型 语法
值类型 where 泛型字母:struct
引用类型 where 泛型字母:class
存在无参公共构造函数,并且是非抽象类型 where 泛型字母:new()
某个类本身或者其派生类 where 泛型字母:类名
某个接口的派生类型 where 泛型字母:接口名
另一个泛型类型本身或者派生类型 where 泛型字母:另一个泛型字母

举例:

class Test1<T> where T : struct
{
}

代表T类型一定是结构体或其他的值类型

class Test2<T, U> where T : U
{
}

interface IFly
{
}

class Test3 : IFly
{
}

//使用
Test2<Test3, IFly> t6 = new Test2<Test3, IFly>();

代表T一定是继承或实现接口U的

约束的组合使用

组合有些不能一起使用,只需要写上去如果报错就说明不能一起组合

注意:一般情况下new()放在最后,否则容易报错

class Test<T> where T : class, new()
{
}

同时多个泛型有约束

直接接在后面即可
class Test<T, K> where T : class, new() where K : struct
{
}

List

本质

List是一个c#为我们封装好的类,它的本质是一个可变类型的泛型数组,List类帮组我们实现了很多方法,比如泛型数组的增删改查。

使用

List<int> list = new List<int>();
List<string> list2 = new List<string>();

//增
list.Add(1);
list2.Add("123");
List<string> listStr = new List<string>();
listStr.Add("123");
list2.AddRange(listStr);
list.Insert(0, 999);

//删
list.Remove(1);
list.RemoveAt(0);
list.Clear();

//查
Console.WriteLine(list[0]);
if (list.Contains(1)
{
    Console.WriteLine("存在元素");
}
//正向查找,找不到时返回-1
int index = list.IndexOf(5);
//反向查找
index = list.LastIndexOf(2);

//改
list[0] = 99;

遍历

//长度
Console.WriteLine(list.Count);
//容量
Console.WriteLine(list.Capacity);
for (int i = 0; i < list.Count; i++)
{
    Console.WriteLine(list[i]);
}
foreach (int item in list)
{
    Console.WriteLine(item);
}

Dictionary

本质

可以将Dictionary理解为拥有泛型的Hashtable

它也是基于键的哈希代码组织起来的键/值对

键值对类型从Hashtable的object变为了可以自己制定的泛型

使用

using System.Collections.Generic
Dictionary<int, string> dictionary = new Dictionary<int, string>();

//增
dictionary.Add(1, "123");

//删
dictionary.Remove(1);
dictionary.Clear();

//查
//1. 通过键查看值
//找不到直接报错
Console.WriteLine(dictionary[2]);
//2. 查看是否存在
//根据键检测
if (dictionary.ContainsKey(4))
{
    Console.WriteLine("存在");
}
//根据值检测
if (dictionary.ContainsValue("1234")
{
    Console.WriteLine("存在");
}

//改
dictionary[1] = "555";

遍历

//长度
Console.WriteLine(dictionary.Count);
//1. 遍历所有键
foreach(int item in dictionary.Keys)
{
    Console.WriteLine(item);
    Console.WriteLine(dictionary[item]);
}
//2. 遍历所有值
foreach(string item in dictionary.Values)
{
    Console.WriteLine(item);
}
//3. 键值对一起遍历,KeyValuePair不好记
foreach(KeyValuePair<int, string> item in dictionary)
{
    Console.WriteLine("键:" + item.Key + "值:" + item.Value);
}

自己实现一个最简单的单向链表

//单向链表节点
class LinkedNode<T>
{
    public T value;
    public LinkedNode<T> nextNode;

    public LinkedNode(T value)
    {
        this.value = value;
}

//单向链表类
class LinkedList<T>
{
    //只是一个引用,没有实例化,指向的实例可以通过add不断改变
    public LinkedNode<T> head;
    public LinkedNode<T> last;

    public void Add(T value)
    {
        LinkedNode<T> node = new LinkedNode<T>(value);
        if (head == null)
        {
            head = node;
            last = node;
        }
        else
        {
            last.nextNode = node;
            last = node;
        }
    }

    public void Remove(T value)
    {
        if (head == null)
        {
            return;
        }
        if (head.value.Equals(value))
        {
            head = head.nextNode;
            if (head == null)
            {
                last = null;
            }
            return;
        }
        LinkedNode<T> node = head;
        while (node.nextNode != null)
        {
            if (node.NextNode.value.Equals(value))
            {
                if (node.NextNode == last)
                {
                    last = node;
                    node.nextNode = null;
                } 
                else 
                {
                    node.nextNode = node.nextNode.nextNode;
                }
                break;
            }
            node = node.nextNode;
        }
    }
}

LinkedList

本质

LinkedList是一个c#为我们封装好的类,它的本质是一个可变类型的泛型双向链表

使用

using System.Collections.Generic

LinkedList<int> linkedList = new LinkedList<int>();

//增
//1. 在链表尾部添加元素
linkedList.AddLast(10);
//2. 在链表头部添加元素
linkedList.AddFirst(20);
//3. 在某一个节点之后添加一个节点
LinkedListNode<int> n = linkedList.Find(20);
linkedList.AddAfter(n, 15);
//4. 在某一个节点之前添加一个节点
linkedList.AddBefore(n, 11);

//删
//1. 移除头节点
linkedList.RemoveFirst();
//2. 移除尾节点
linkedList.RemoveLast();
//3. 移除指定节点
linkedList.Remove(20);
//4. 清空
linkedList.Clear();

//查
//1. 头节点
LinkedListNode<int> first = linkedList.First;
//2. 尾节点
LinkedListNode<int> last = linkedList.Last;
//3. 查找指定值的节点
//只能遍历查找
//找不到时会返回空
LinkedListNode<int> node = linkedList.Find(3);
//4. 判断是否存在
if (linkedList.Contains(1))
{
    Console.WriteLine("链表中存在");
}

//改
//要先得到节点,再改变其中的值
linkedList.First.Value = 10;

遍历

//1. foreach遍历
foreach(int item in linkedList)
{
    Console.WriteLine(item);
}
//2. 通过节点遍历
//从头到尾
LinkedListNode<int> nowNode = linkedList.First;
while (nowNode != null)
{
    Console.WriteLine(nowNode.value);
    nowNode = nowNodw.Next;
}
//从尾到头
nowNode = linkedList.Last;
while(nowNode != null)
{
    Consolw.WriteLine(nowNode.Value);
    nowNode = nowNode.Previous;
}

泛型Stack

使用上和之前的Stack一模一样
Stack<int> stack = new Stack<int>();

泛型Queue

使用上和之前的Queue一模一样
Queue<object> queue = new Queue<object>();
posted @ 2025-07-28 17:52  柠凉w  阅读(18)  评论(0)    收藏  举报