泛型是 C# 2.0 引入的核心特性,它允许在定义类、接口、方法、委托等时使用未指定的类型参数,在使用时再指定具体类型。这种机制可以显著提高代码的复用性、类型安全性和性能。

一、泛型的核心概念
  1. 类型参数化
    泛型允许将类型作为 "参数" 传递给类、方法等,就像方法可以接受数值参数一样。例如,List<T> 中的 T 就是类型参数,使用时可以指定为 List<int>List<string> 等。

  2. 编译时类型检查
    泛型在编译阶段就会进行类型验证,避免了运行时的类型转换错误。例如,List<int> 只能存储 int 类型,编译器会阻止添加字符串等其他类型。

  3. 消除装箱 / 拆箱操作
    对于值类型(如 intdouble),非泛型集合(如 ArrayList)会将值类型装箱为 object,取出时再拆箱,造成性能损耗。泛型集合(如 List<int>)直接存储值类型,避免了这一过程。

  4. 代码复用
    一套泛型代码可以适配多种数据类型,无需为每种类型重复编写逻辑(如排序、查找等)。

二、泛型的基本使用
1. 泛型类(Generic Classes)

泛型类是最常用的泛型形式,定义时在类名后添加 <类型参数>,使用时指定具体类型。

// 定义泛型类
public class MyGenericClass<T>
{private T _value;public MyGenericClass(T value){_value = value;}public T GetValue(){return _value;}public void SetValue(T value){_value = value;}
}// 使用泛型类
var intContainer = new MyGenericClass<int>(10);
int intValue = intContainer.GetValue(); // 10var stringContainer = new MyGenericClass<string>("Hello");
string stringValue = stringContainer.GetValue(); // "Hello"
2. 泛型方法(Generic Methods)

泛型方法可以在普通类或泛型类中定义,方法名后添加 <类型参数>,调用时可显式或隐式指定类型。

public class GenericMethodExample
{// 定义泛型方法public T Max<T>(T a, T b) where T : IComparable<T>{return a.CompareTo(b) > 0 ? a : b;}
}// 使用泛型方法
var example = new GenericMethodExample();
int maxInt = example.Max(5, 10); // 10(隐式推断类型为int)
string maxStr = example.Max<string>("apple", "banana"); // "banana"(显式指定类型)
3. 泛型接口(Generic Interfaces)

泛型接口与泛型类类似,常用于定义集合、比较器等具有通用性的契约。 

// 定义泛型接口
public interface IRepository<T>
{T GetById(int id);void Add(T item);void Update(T item);void Delete(int id);
}// 实现泛型接口(以用户仓储为例)
public class UserRepository : IRepository<User>
{public User GetById(int id) { /* 实现 */ }public void Add(User item) { /* 实现 */ }public void Update(User item) { /* 实现 */ }public void Delete(int id) { /* 实现 */ }
}
4. 泛型委托(Generic Delegates)

泛型委托允许定义可接受不同类型参数的委托,C# 内置的 Func<T>Action<T> 就是典型例子。

// 定义泛型委托
public delegate T Transformer<T>(T input);// 使用泛型委托
public class DelegateExample
{public static int Square(int x) => x * x;public static string ToUpper(string s) => s.ToUpper();
}// 调用
Transformer<int> intTransformer = DelegateExample.Square;
int result = intTransformer(5); // 25Transformer<string> stringTransformer = DelegateExample.ToUpper;
string upperStr = stringTransformer("hello"); // "HELLO"
5. 泛型约束(Constraints)

泛型约束用于限制类型参数的范围,确保类型参数满足特定条件(如必须实现某接口、必须是引用类型等)。常用约束如下:

约束语法说明
where T : structT 必须是值类型(非 Nullable<T>
where T : class
T 必须是引用类型
where T : new()T 必须有公共无参构造函数
where T : 基类名T 必须是指定基类或其派生类
where T : 接口名
T 必须实现指定接口
where T : UT 必须是 U 或其派生类(用于多参数)

示例:

// 约束T必须实现IComparable<T>接口
public class GenericWithConstraint<T> where T : IComparable<T>
{public T FindMax(T[] items){if (items == null || items.Length == 0)throw new ArgumentException("数组不能为空");T max = items[0];foreach (var item in items){if (item.CompareTo(max) > 0)max = item;}return max;}
}
6. 泛型集合(Generic Collections)

.NET Framework 提供了丰富的泛型集合类(位于 System.Collections.Generic 命名空间),替代了非泛型集合(如 ArrayListHashtable):

  • List<T>:动态数组,替代 ArrayList
  • Dictionary<TKey, TValue>:键值对集合,替代 Hashtable
  • HashSet<T>:无序唯一元素集合
  • Queue<T>:先进先出(FIFO)队列
  • Stack<T>:后进先出(LIFO)栈

示例:

using System.Collections.Generic;// 使用List<T>
var numbers = new List<int> { 1, 2, 3 };
numbers.Add(4);
int first = numbers[0];// 使用Dictionary<TKey, TValue>
var personAges = new Dictionary<string, int>
{{ "Alice", 30 },{ "Bob", 25 }
};
int aliceAge = personAges["Alice"];
三、泛型的高级特性
1. 泛型类型参数的协变与逆变
  • 协变(Covariance):允许将泛型类型参数从派生类隐式转换为基类,使用 out 关键字标记(仅适用于接口和委托)。
  • 逆变(Contravariance):允许将泛型类型参数从基类隐式转换为派生类,使用 in 关键字标记(仅适用于接口和委托)。

示例:

// 协变接口(out关键字)
public interface IEnumerable<out T> { ... }// 逆变接口(in关键字)
public interface IComparer<in T> { ... }// 用法
IEnumerable<string> strings = new List<string>();
IEnumerable<object> objects = strings; // 协变:string → objectIComparer<object> objectComparer = new ObjectComparer();
IComparer<string> stringComparer = objectComparer; // 逆变:object → string
2. 静态字段与泛型

泛型类的静态字段在不同封闭类型(如 MyClass<int> 和 MyClass<string>)中是独立的,不会共享:

public class StaticGeneric<T>
{public static int Count { get; set; } = 0;
}// 不同类型的静态字段独立
StaticGeneric<int>.Count = 1;
StaticGeneric<string>.Count = 2;
Console.WriteLine(StaticGeneric<int>.Count); // 1(与string的Count无关)

List<int> 本质上是泛型类 List<T> 的一个实例化版本,它依赖于泛型机制才能存在。如果没有 List<T> 这个泛型定义,就无法通过传入 int 得到 List<int>

T 是泛型的 "模板参数",而 int 是填充这个模板的 "实际参数"。List<int> 是泛型机制的产物,因此它是泛型集合的典型应用。

3. 泛型类型的反射

可以通过反射获取泛型类型的信息,如类型参数、约束等:

Type listType = typeof(List<int>);
if (listType.IsGenericType)
{Type genericTypeDefinition = listType.GetGenericTypeDefinition(); // 得到List<T>Type[] typeArguments = listType.GetGenericArguments(); // 得到[int]
}
四、泛型的优势总结
  1. 类型安全:编译时检查类型,避免运行时类型转换错误。
  2. 性能优化:减少装箱 / 拆箱操作,尤其对值类型更高效。
  3. 代码复用:一套逻辑适配多种类型,减少重复代码。
  4. 灵活性:结合约束、协变、逆变等特性,可适应复杂场景。
五、泛型的适用场景
  • 集合类(如自定义列表、字典)
  • 工具类(如转换器、比较器)
  • 数据访问层(如通用仓储模式)
  • 委托和事件(如通用回调函数)
  • 算法实现(如排序、搜索,适用于多种数据类型)

通过泛型,C# 代码可以在保持类型安全的同时实现高度复用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/93200.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/93200.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/93200.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring中存在两个相同的Bean是否会报错?

第一种情况&#xff1a;使用XML的方式设置Bean&#xff0c;这种情况在Spring启动时就会报错&#xff0c;因为ID在Spring中是Bean的唯一标识&#xff0c;Spring容器在启动时会校验唯一性&#xff0c;一旦发现重复就会报错。但是如果是在两个不同的XML文件中定义两个相同的Bean&a…

【新手入门】Android基础知识(一):系统架构

目 录 Android 系统架构图 1. 应用 2. JAVA API 框架 3. 原生 C/C 库 4. Android 运行时&#xff08;Android Runtime&#xff09; 5. 硬件抽象层 (HAL) 6. Linux 内核 参考资料 Android 系统架构图 Android底层内核空间以Linux Kernel作为基石&#xff0c;上层用户空…

晶振电路的负载电容、电阻参数设计

系列文章目录 文章目录系列文章目录前言一、晶振主要参数二、有源与无源区别三、无源晶振四、有源晶振总结前言 在硬件电路的设计中&#xff0c;晶振电路是必不可少的&#xff0c;它充当了整个电路心脏的作用。在这个晶振电路的设计中负载电容、电阻参数的选型是很重要的&…

电脑上练打字用什么软件最好:10款打字软件评测

现在孩子们在电脑上练打字&#xff0c;软件一搜一大把&#xff0c;可好多家长和老师都犯愁&#xff1a;到底哪个管用&#xff1f;我带200多个小学生练过字&#xff0c;前前后后试了十款软件&#xff0c;今天就掏心窝子说说——有的看着花哨其实没用&#xff0c;有的专业是专业但…

第五天~提取Arxml的模板信息

🌟 ARXML模板信息提取:解锁汽车软件的乐高魔法 在汽车电子的世界里,AUTOSAR(汽车开放系统架构)如同无形的神经系统,而ARXML文件正是承载这套神经系统蓝图的数字载体。当工程师们需要批量创建或修改ECU(电子控制单元)配置时,模板信息提取便成为了一项至关重要的核心技…

react+antd+vite自动引入组件、图标等

前言&#xff1a;react在使用antd的时候&#xff0c;也是需要每个组件都在界面上按需引入的&#xff0c;那能不能自动生成&#xff0c;按需使用呢&#xff1f;我们这里说一说这个。安装插件&#xff0c;组件按需引入unplugin-antd-resolverunplugin-auto-importnpm install unp…

深度学习与遥感入门(六)|轻量化 MobileNetV2 高光谱分类

系列回顾&#xff1a; &#xff08;一&#xff09;CNN 基础&#xff1a;高光谱图像分类可视化全流程 &#xff08;二&#xff09;HybridNet&#xff08;CNNTransformer&#xff09;&#xff1a;提升全局感受野 &#xff08;三&#xff09;GCN 入门实战&#xff1a;基于光谱 KNN…

第4节 神经网络从公式简化到卷积神经网络(CNN)的进化之路

🧙 深度学习的"玄学进化史" 从CNN用卷积层池化层处理图片,循环网络RNN如何利用上下文处理序列数据,到注意力机制让Transformer横空出世,现在的大语言模型已经能写能画能决策!每个新技巧都让人惊呼"还能这么玩",难怪说深度学习像玄学——但这玄学,…

最新去水印小程序系统 前端+后端全套源码 多套模版 免授权(源码下载)

最新去水印小程序系统 前端后端全套源码 多套模版 免授权 源码下载&#xff1a;https://download.csdn.net/download/m0_66047725/91669468 更多资源下载&#xff1a;关注我

TCP Socket 编程实战:实现简易英译汉服务

前言&#xff1a;TCP&#xff08;传输控制协议&#xff09;是一种面向连接、可靠的流式传输协议&#xff0c;与 UDP 的无连接特性不同&#xff0c;它通过三次握手建立连接、四次挥手断开连接&#xff0c;提供数据确认、重传机制&#xff0c;保证数据有序且完整传输。本文将基于…

CF566C Logistical Questions Solution

Description 给定一棵 nnn 个点的树 TTT&#xff0c;点有点权 aia_iai​&#xff0c;边有边权 www. 定义 dist⁡(u,v)\operatorname{dist}(u,v)dist(u,v) 为 u→vu\to vu→v 的简单路径上的边权和. 找到一个节点 uuu&#xff0c;使得 W∑i1ndist⁡(u,i)32aiW\sum\limits_{i1}^n…

聊天室全栈开发-保姆级教程(Node.js+Websocket+Redis+HTML+CSS)

前言 最近在学习websocket全双工通信&#xff0c;想要做一个联机小游戏&#xff0c;做游戏之前先做一个聊天室练练手。 跟着本篇博客&#xff0c;可以从0搭建一个属于你自己的聊天室。 准备阶段 什么人适合学习本篇文章&#xff1f; 答&#xff1a;前端开发者&#xff0c;有一…

后台管理系统-2-vue3之路由配置和Main组件的初步搭建布局

文章目录1 路由搭建1.1 路由创建(router/index.js)1.2 路由组件(views/Main.vue)1.3 路由引入并注册(main.js)1.4 路由渲染(App.vue)2 element-plus的应用2.1 完整引入并注册(main.js)2.2 示例应用(App.vue)3 ElementPlusIconsVue的应用3.1 图标引入并注册(main.js)3.2 示例应用…

使用 Let’s Encrypt 免费申请泛域名 SSL 证书,并实现自动续期

使用 Let’s Encrypt 免费申请泛域名 SSL 证书&#xff0c;并实现自动续期 目录 使用 Let’s Encrypt 免费申请泛域名 SSL 证书&#xff0c;并实现自动续期 &#x1f6e0;️ 环境准备&#x1f4a1; 什么是 Let’s Encrypt&#xff1f;&#x1f9e0; Let’s Encrypt 证书颁发原…

一键自动化:Kickstart无人值守安装指南

Kickstart文件实现自动安装1. Kickstart文件概述1.1 定义与作用Kickstart文件是Red Hat系Linux发行版&#xff08;如RHEL、CentOS、Fedora&#xff09;用于实现自动化安装的配置文件&#xff0c;采用纯文本格式保存。它通过预设安装参数的方式&#xff0c;使系统安装过程无需人…

深度解读 Browser-Use:让 AI 驱动浏览器自动化成为可能

目录 一、什么是 Browser-Use&#xff1f; 二、Browser-Use 的核心功能 1. AI 与浏览器的链接桥梁 2. 无代码 / 低代码操作界面 3. 支持多家 LLM 4. 开发体验简洁 可快速上手 三、核心价值与适用场景 四、与 Playwright 的结合使用 五、总结与展望 https://github.com…

React.memo、useMemo 和 React.PureComponent的区别

useMemo 和 React.memo 都是 React 提供的性能优化工具&#xff0c;但它们的作用和使用场景有显著不同。以下是两者的全面对比&#xff1a; 一、核心区别总结特性useMemoReact.memo类型React Hook高阶组件(HOC)作用对象缓存计算结果缓存组件渲染结果优化目标避免重复计算避免不…

Lumerical INTERCONNECT ------ CW Laser 和 OPWM 组成的系统

Lumerical INTERCONNECT ------ CW Laser 和 OPWM 组成的系统 引言 正文 引言 这里我们来简单介绍一下 CW Laser 与 OSA 组成的简单系统结构的仿真。 正文 我们构建一个如下图所示的仿真结构。 我们将 CWL 中的 power 设置为 1 W。 然后直接运行仿真查看结果如下: 虽然 …

想涨薪30%?别只盯着大厂了!转型AI产品经理的3个通用方法,人人都能学!

在AI产品经理刚成为互联网公司香饽饽的时候&#xff0c;刚做产品1年的月月就规划了自己的转型计划&#xff0c;然后用3个月时间成功更换赛道&#xff0c;转战AI产品经理&#xff0c;涨薪30%。 问及她有什么上岸秘诀&#xff1f;她也复盘总结了3个踩坑经验和正确路径&#xff0c…

基于Hadoop的全国农产品批发价格数据分析与可视化与价格预测研究

文章目录有需要本项目的代码或文档以及全部资源&#xff0c;或者部署调试可以私信博主项目介绍每文一语有需要本项目的代码或文档以及全部资源&#xff0c;或者部署调试可以私信博主 项目介绍 随着我国农业数字化进程的加快&#xff0c;农产品批发市场每天都会产生海量的价格…