C# 语言进阶(九)泛型、内置集合、Socket网络

C# 语言进阶(九)泛型、内置集合、Socket网络
本篇核心知识点泛型泛型类 / 泛型方法、泛型约束、协变与逆变、C# 内置集合Hashtable、Dictionary、ArrayList、List、Queue/Stack、Socket 网络编程、TCP/UDP 协议、服务端 客户端基础流程、端口与 IP 规范、阻塞方法一、C# 泛型Generic1.泛型基础概念定义泛型是一种类型参数化机制使用T/K/V等占位符代表未知类型编译时确定真实类型一套代码适配多种数据类型消除重复重载。核心优势编译期类型检查类型错误提前捕获避免值类型装箱、拆箱提升运行性能大幅减少重复模板代码复用逻辑。基础语法分类泛型类、泛型方法、泛型委托、泛型接口。1泛型类概念类名后加T整个类内部均可使用T作为数据类型实例化时尖括号指定真实类型。完整代码示例using System; // 单个泛型参数容器类 public class ContainerT{ private T _data; // 存储数据 public void SetData(T val){ _data val; } // 获取数据 public T GetData(){ return _data; } } static void Main(){ // 指定T为int Containerint intBox new Containerint(); intBox.SetData(100); Console.WriteLine(intBox.GetData()); ​ // 指定T为字符串 Containerstring strBox new Containerstring(); strBox.SetData(游戏道具); } 多泛型参数字典场景 K/V // 双泛型KeyValue public class MyDicK,V{ private K _key; private V _value; public void Set(K k, V v){ _key k; _value v; } } // 使用 MyDicstring,int dic new MyDicstring,int();2泛型方法概念方法名前加T仅当前方法使用泛型类本身无需泛型。代码示例public class Tool{ // 泛型打印方法 public static void PrintT(T msg){ Console.WriteLine(msg); } } static void Main(){ Tool.Printint(666); Tool.Printstring(测试文字); // 编译器自动推导类型可省略T Tool.Print(99.9f); }2.泛型约束 where核心考点概念通过where T : 约束限制泛型可传入的类型否则编译器无法识别类型成员无法调用属性 / 方法。五类约束规则值类型约束where T : structT 只能是 struct、int、bool 等值类型禁止 class 引用类型引用类型约束where T : classT 只能是类、接口、委托等引用类型不能是值类型无参构造约束where T : new()T 必须拥有公共无参构造函数代码内可new T()创建对象若类只写带参构造默认无参构造消失会编译报错基类约束where T : 父类名T 必须是该父类 / 抽象类的派生类可调用父类全部 public/protected 方法接口约束where T : 接口名T 必须实现指定接口可调用接口定义方法。多重约束逗号分隔// 同时满足引用类型 无参构造 实现IMsg接口 public class MsgPoolT where T : class, IGameMsg, new(){ public T CreateMsg(){ return new T(); // 必须new约束才能创建 } }约束报错示例class Dog{ // 仅带参构造无默认无参构造 public Dog(string name) { } } // 约束要求无参构造传入Dog直接报错 class TestT where T : new() { } // TestDog 编译失败3.协变 out / 逆变 in泛型接口 / 委托专用协变out T输出类型允许派生类实例赋值给基类变量返回值场景逆变in T输入类型允许基类实例传入派生类型参数入参场景限制仅能修饰泛型接口、泛型委托普通泛型类不能使用 in/out作用拓宽泛型类型转换灵活性编译校验类型安全。4.泛型委托概念委托参数、返回值可使用泛型一套委托适配任意参数 / 返回类型替代大量重复委托定义。// 泛型委托接收T返回R delegate R CalcT,R(T input); static void Main(){ Calcint, string func num num.ToString(); Console.WriteLine(func(123)); }5.泛型拓展优缺点优点类型安全、无装箱拆箱、代码复用缺点无法直接对泛型做加减等运算无统一数值接口必须加约束工程场景游戏道具容器、消息池、自定义链表 / 队列优先使用泛型。二、C# 内置集合类容器1.Hashtable 非泛型哈希表概念系统早期键值容器key/value 全部为 object 类型无泛型约束存入值类型自动装箱取出强制拆箱性能差。特性键不允许重复无序存储取值方式ht[key]不存在返回 null不抛异常遍历方式遍历 Keys 集合或迭代器遍历 DictionaryEntry代码示例using System.Collections; static void Main(){ Hashtable ht new Hashtable(); ht.Add(玩家1, 2000); ht.Add(玩家2, 3500); // 按键遍历 foreach(string key in ht.Keys){ Console.WriteLine(${key}:{ht[key]}); } }缺陷任意类型可存入类型混杂时取值极易转换异常新项目优先 Dictionary。2.DictionaryK,V 泛型字典游戏高频概念泛型哈希键值容器严格约束 Key、Value 类型无装箱拆箱性能远优于 Hashtable。核心特性Key 唯一底层哈希表两种取值dic[key]键不存在直接程序崩溃dic.TryGetValue(key, out var val)安全取值返回 bool推荐项目使用工程用途资源缓存名字对应预制 / 音效、玩家数据存储完整代码using System.Collections.Generic; static void Main(){ Dictionarystring, int playerHp new Dictionarystring, int(); player.Add(战士, 5000); // 安全取值 int hp; if(playerHp.TryGetValue(战士, out hp)){ Console.WriteLine(血量 hp); } else{ Console.WriteLine(该玩家不存在); } }3.ArrayList 非泛型动态数组概念早期动态数组存储 object任意类型均可添加无类型约束频繁装箱拆箱新项目废弃。缺陷同一容器存 int、string、自定义类时取出强制转换极易报错替代方案泛型ListT4.ListT 泛型动态数组最常用概念长度可变泛型数组连续内存支持增删改查、排序、遍历特性尾部添加 O (1)中间插入需要挪动元素泛型约束类型统一无装箱游戏场景道具列表、怪物列表、玩家列表5.QueueT / StackT 泛型队列、栈QueueFIFO 先进先出网络消息队列核心载体StackLIFO 先进后出DFS、撤销功能多线程操作容器时读写必须加lock互斥锁防止数据错乱。集合对比总结容器泛型底层性能适用场景Hashtable否哈希差装箱老旧项目兼容Dictionary是哈希高资源缓存、键值映射ArrayList否数组差淘汰ListT是动态数组高批量同类型数据三、Socket 网络编程基础TCP/UDP1.Socket 核心概念Socket套接字是操作系统提供网络通信接口所有客户端、服务器数据收发底层全部依赖 Socket分为 TCP、UDP 两套传输协议。2.TCP 与 UDP 完整对比TCP 传输控制协议特性面向连接、可靠传输、字节流连接流程三次握手建立连接四次挥手断开优点数据不丢失、不乱序、重传机制保证可靠缺点握手挥手额外开销存在网络延迟适用场景登录、任务、交易、回合制战斗等核心业务数据不能丢失。UDP 数据报协议特性无连接、不可靠、数据报优点无握手传输速度极快低延迟缺点无重传数据可能丢失、乱序优化方案手动添加消息序列号、丢失重传逻辑适用场景FPS / 赛车实时位置同步、角色动作、特效同步市面游戏主流方案TCP 存核心数据UDP 同步实时状态混合使用。通俗类比TCP 打电话必须接通才能对话掉线双方感知UDP 发短信直接发送对方不在线消息丢失。3.IP 地址 端口 概念IP设备网络唯一地址本机测试固定回环地址127.0.0.1IPv4 四段 0~255 数字端口一台机器内程序区分标识范围 0~65535规范系统占用知名端口80 网页、3306 数据库不要使用项目选用 8000~10000 区间冲突同一端口同一时间仅能一个程序占用否则绑定失败。4.TCP Socket 服务端完整执行流程引入命名空间using System.Net; using System.Net.Sockets;创建 Socket协议类型选SocketType.StreamTCP 字节流Bind 绑定本机 IP 与端口Listen 设置最大监听连接数Accept 阻塞等待客户端连接无客户端则卡死阻塞方法连接成功得到客户端专属 SocketSend 发送数据、Receive 接收数据Shutdown/Close 关闭套接字。服务端关键代码片段Socket serverSocket new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPAddress ip IPAddress.Parse(127.0.0.1); IPEndPoint ep new IPEndPoint(ip, 8080); serverSocket.Bind(ep); serverSocket.Listen(100); Console.WriteLine(服务器等待连接...); Socket clientSocket serverSocket.Accept(); // 阻塞 Console.WriteLine(客户端已连接);5.TCP Socket 客户端执行流程创建同类型 Socket构造服务端 IP 端口端点Connect 发起连接无需 Bind、Listen、Accept连接成功后 Send/Receive 收发数据客户端关键代码Socket client new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPEndPoint serverEp new IPEndPoint(IPAddress.Parse(127.0.0.1), 8080); client.Connect(serverEp);6.阻塞方法说明Accept()、Receive()、Console.ReadKey()均为阻塞方法执行时线程暂停等待触发条件才继续游戏主线程直接使用会界面卡死网络操作必须新开子线程。7.TCP 特有问题粘包TCP 基于连续字节流多条消息连续发送时字节合并无法区分消息边界解决方案每条消息头部附加数据长度接收时按长度拆分数据包UDP 无粘包问题一次发送对应一次接收。四、拓展1 泛型约束五类作用new 无参构造使用场景2 Dictionary 对比 Hashtable 性能差异TryGetValue 安全取值3 List/Queue 多线程操作必须加 lock 锁4 TCP/UDP 核心差异、游戏业务选型5 Socket 服务端与客户端代码流程区分6 端口取值规范、127.0.0.1 回环地址作用7 阻塞线程带来的游戏界面卡死解决方案多线程异步网络。