深入解析 C# 中的泛型:概念、用法与最佳实践
C# 中的 泛型(Generics) 是一种强大的编程特性,允许开发者在不预先指定具体数据类型的情况下编写代码。通过泛型,C# 能够让我们编写更灵活、可重用、类型安全且性能优良的代码。泛型广泛应用于类、方法、接口、委托、集合等多个方面。
本文将详细介绍 C# 中泛型的基本概念、常见用法、类型约束以及一些高级应用,帮助你更深入地理解泛型的强大功能及其最佳实践。
一、泛型的基本概念
1.1 什么是泛型?
泛型使得你能够编写能够操作多种数据类型的代码,而不需要在代码中硬编码具体的数据类型。通过类型参数(例如 T
),你可以在运行时决定具体的类型,从而提高代码的重用性和灵活性。
在 C# 中,泛型可以应用于:
- 泛型类
- 泛型方法
- 泛型接口
- 泛型委托
- 泛型集合
1.2 泛型类
泛型类 是在定义类时使用类型参数,并且在类的实例化时指定具体的类型。这使得同一个类可以用来处理不同类型的数据。
示例:
public class Box<T>
{private T _value;public void SetValue(T value){_value = value;}public T GetValue(){return _value;}
}public class Program
{public static void Main(){Box<int> intBox = new Box<int>();intBox.SetValue(123);Console.WriteLine(intBox.GetValue()); // 输出 123Box<string> stringBox = new Box<string>();stringBox.SetValue("Hello");Console.WriteLine(stringBox.GetValue()); // 输出 Hello}
}
在这个例子中,Box<T>
是一个泛型类,T
是类型参数。通过不同的类型参数,Box
类可以同时处理不同的数据类型。
1.3 泛型方法
泛型方法 允许你在方法定义时使用类型参数。方法可以在调用时决定具体的类型。
示例:
public class Program
{public static void Print<T>(T value){Console.WriteLine(value);}public static void Main(){Print(123); // 输出 123Print("Hello"); // 输出 HelloPrint(3.14); // 输出 3.14}
}
Print<T>
方法能够处理不同类型的数据,并且在调用时根据传入的参数类型来自动推断 T
的类型。
1.4 泛型接口
泛型接口 允许接口声明时不指定具体的类型,而是在实现该接口的类中指定具体类型。通过这种方式,接口可以与多种数据类型兼容。
示例:
public interface IStorage<T>
{void Add(T item);T Get(int index);
}public class StringStorage : IStorage<string>
{private List<string> items = new List<string>();public void Add(string item){items.Add(item);}public string Get(int index){return items[index];}
}public class Program
{public static void Main(){IStorage<string> storage = new StringStorage();storage.Add("Item 1");storage.Add("Item 2");Console.WriteLine(storage.Get(0)); // 输出 Item 1}
}
在这个例子中,IStorage<T>
是一个泛型接口,StringStorage
类实现了该接口,并且指定 T
为 string
类型。
二、泛型类型参数的约束
C# 允许你为泛型类型参数添加约束,以确保泛型在特定类型范围内使用,从而提升类型安全性。
2.1 常见的泛型约束
class
:限制类型参数为引用类型。struct
:限制类型参数为值类型。new()
:限制类型参数必须有无参数构造函数。where T : BaseClass
:限制类型参数为某个特定的类或接口。
2.2 约束示例
示例1:限制类型为值类型
public class ValueTypeContainer<T> where T : struct
{private T _value;public ValueTypeContainer(T value){_value = value;}public void Display(){Console.WriteLine(_value);}
}public class Program
{public static void Main(){ValueTypeContainer<int> intContainer = new ValueTypeContainer<int>(123);intContainer.Display(); // 输出 123// 编译错误:不能传递引用类型// ValueTypeContainer<string> stringContainer = new ValueTypeContainer<string>("Hello");}
}
示例2:使用接口约束
public interface IComparable
{int CompareTo(object obj);
}public class Repository<T> where T : IComparable
{public void Print(T item){Console.WriteLine(item.ToString());}
}public class Program
{public static void Main(){Repository<string> repo = new Repository<string>();repo.Print("Hello"); // 输出 Hello}
}
2.3 多个约束的使用
你可以为一个泛型类型参数指定多个约束,确保泛型类型满足多个条件。
示例:
public class Repository<T> where T : class, IComparable, new()
{public void Print(T item){Console.WriteLine(item.ToString());}
}
三、泛型的高级用法
3.1 多个类型参数
泛型不仅支持一个类型参数,还可以支持多个类型参数,这使得你可以创建更加灵活的泛型类型。
示例:
public class Pair<T1, T2>
{private T1 first;private T2 second;public Pair(T1 first, T2 second){this.first = first;this.second = second;}public void Print(){Console.WriteLine($"First: {first}, Second: {second}");}
}public class Program
{public static void Main(){Pair<int, string> pair = new Pair<int, string>(1, "One");pair.Print(); // 输出 First: 1, Second: One}
}
3.2 泛型与集合类
C# 的泛型集合类(如 List<T>
、Dictionary<TKey, TValue>
、Queue<T>
等)允许我们高效地操作数据,并且避免了类型转换的潜在问题。
示例:
List<int> numbers = new List<int>();
numbers.Add(1);
numbers.Add(2);
numbers.Add(3);
Console.WriteLine(numbers[0]); // 输出 1
3.3 泛型委托
泛型委托使得委托能够处理多种类型的方法。你可以定义一个泛型委托,使其接受不同类型的参数,并且在运行时动态选择具体的方法。
示例:
public delegate void PrintDelegate<T>(T value);public class Program
{public static void Main(){PrintDelegate<int> printInt = (value) => Console.WriteLine(value);printInt(10); // 输出 10PrintDelegate<string> printString = (value) => Console.WriteLine(value);printString("Hello"); // 输出 Hello}
}
3.4 泛型与 LINQ
C# 的 LINQ 查询使用泛型来确保查询结果的类型安全。你可以利用 LINQ 对集合进行高效的查询、排序和过滤操作。
示例:
List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
var evenNumbers = numbers.Where(n => n % 2 == 0).ToList();foreach (var num in evenNumbers)
{Console.WriteLine(num); // 输出 2, 4
}
四、泛型的优势
- 类型安全:泛型提供编译时的类型检查,避免了运行时类型错误。
- 性能优化:泛型避免了类型转换的开销,因此在处理大量数据时具有较好的性能。
- 代码重用:通过泛型,我们可以编写能够处理多种类型数据的代码,而无需重复编写多个版本。
- 灵活性:泛型使得我们能够编写通用的代码,且不需要牺牲类型安全。
五、总结
泛型是 C# 中的一项强大特性,能够让你编写类型安全、灵活、可重用且高效的代码。通过泛型,开发者可以避免在类型转换时出现的错误,并且能够编写高度通用的类、方法、接口等。掌握泛型的使用,能够帮助开发者在处理复杂数据结构和编写高效代码时更得心应手。
无论是常见的泛型类、方法、接口,还是泛型在 LINQ 和集合类中的应用,了解泛型的各种用法和最佳实践,能够使你写出更简洁、更可维护的代码。
相关文章:

深入解析 C# 中的泛型:概念、用法与最佳实践
C# 中的 泛型(Generics) 是一种强大的编程特性,允许开发者在不预先指定具体数据类型的情况下编写代码。通过泛型,C# 能够让我们编写更灵活、可重用、类型安全且性能优良的代码。泛型广泛应用于类、方法、接口、委托、集合等多个方…...

NUMA架构介绍
NUMA 架构详解 NUMA(Non-Uniform Memory Access,非统一内存访问) 是一种多处理器系统的内存设计架构,旨在解决多处理器系统中内存访问延迟不一致的问题。与传统的 UMA(Uniform Memory Access,统一内存访问…...

数据安全VS创作自由:ChatGPT与国产AI工具隐私管理对比——论文党程序员必看的避坑指南
文章目录 数据安全VS创作自由:ChatGPT与国产AI工具隐私管理对比——论文党程序员必看的避坑指南ChatGPTKimi腾讯元宝DeepSeek 数据安全VS创作自由:ChatGPT与国产AI工具隐私管理对比——论文党程序员必看的避坑指南 产品隐私设置操作路径隐私协议ChatGPT…...

python爬虫:python中使用多进程、多线程和协程对比和采集实践
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 1. 多进程爬虫1.1 python多进程样例1.2 实现多进程爬虫2. 多线程爬虫2.1 python多线程样例2.2 实现多线程爬虫3. 协程爬虫3.1 python协程样例3.2 实现协程爬虫在网络爬虫中,为了提高抓取效率,常常需要使用多进程、多线…...

《OpenCV》—— dlib库
文章目录 dlib库是什么?OpenCV库与dlib库对比dlib库安装dlib——人脸应用实例——人脸检测dlib——人脸应用实例——人脸关键点定位dlib——人脸应用实例——人脸轮廓绘制 dlib库是什么? OpenCV库与dlib库对比 dlib库安装 dlib——人脸应用实例——人脸检…...

Linux搜索---find
find搜索 find 命令的核心功能是在指定的目录路径下,递归地搜索文件和目录,并且可以根据多种条件对搜索结果进行筛选,还能对符合条件的文件和目录执行特定操作。 一、基础语法结构 find [起始目录] [匹配条件] [执行操作] # 基本示例 find…...

python之爬虫入门实例
链家二手房数据抓取与Excel存储 目录 开发环境准备爬虫流程分析核心代码实现关键命令详解进阶优化方案注意事项与扩展 一、开发环境准备 1.1 必要组件安装 # 安装核心库 pip install requests beautifulsoup4 openpyxl pandas# 各库作用说明: - requests&#x…...

Blender常用快捷键的汇总
一、基础操作 全选/取消全选:A(全选)、AA(连续按两次A取消全选)复制物体:Shift D(复制后需点击确认位置)移动物体:G(按X/Y/Z可约束轴向移动)旋转…...

鸿蒙启动页开发
鸿蒙启动页开发 1.1 更改应用名称和图标 1.更改应用图标 找到moudle.json5文件,找到应用启动的EntryAbility下面的icon,将原来的图标改成自己设置的即可 2.更改应用名称 3.效果展示 2.1 广告页面开发 3.1 详细介绍 3.1.1 启动页面 import { PrivacyDialog } fr…...

Unity 文字高度自适应
期望 文字有字号限制,输入文字文字后先判断高度是否适用于限制字号,若处于最小字号时高度任不适用,则调整RectTransform 的高度。 核心代码 每次输入文字时先将字号设定为原始字号。 comp.fontSize fontSize; comp.text content; 拓展T…...

Teaching Small Language Models Reasoning throughCounterfactual Distillation
2024.emnlp-main.333.pdfhttps://aclanthology.org/2024.emnlp-main.333.pdf 1.概述 大型语言模型(LLM),如GPT-3,在各种下游任务中表现出色,包括通过链式思维(CoT)进行问题解答。CoT鼓励模型在解决问题时生成中间推理步骤。尽管LLM取得了成功,但由于模型大小的限制,其…...

快速开始React开发(一)
快速开始React开发(一) React是一个JavaScript库,用于构建交互式网站,并且能够快捷创建SPA(Single Page App),其组件化的思想也是被一再传播,无论是普通的Web网站还是嵌入移动端交互…...

2025最新Transformer模型及深度学习前沿技术应用
第一章、注意力(Attention)机制 1、注意力机制的背景和动机(为什么需要注意力机制?注意力机制的起源和发展里程碑)。 2、注意力机制的基本原理(什么是注意力机制?注意力机制的数学表达与基本公…...

极狐GitLab 正式发布安全版本17.9.1、17.8.4、17.7.6
本分分享极狐GitLab 补丁版本 17.9.1、17.8.4、17.7.6 的详细内容。这几个版本包含重要的缺陷和安全修复代码,我们强烈建议所有私有化部署用户应该立即升级到上述的某一个版本。对于极狐GitLab SaaS,技术团队已经进行了升级,无需用户采取任何…...

[环境搭建篇] Windows 环境下如何安装Docker工具
Windows 环境下如何安装Docker工具 1. 检查系统要求2. 启用WSL 2和虚拟化步骤一:启用WSL步骤二:启用虚拟化(Hyper-V)步骤三:安装WSL 2内核 3. 安装Docker Desktop4. 配置Docker5. 家庭版用户替代方案6. 常见问题解决问…...

JavaScript 数组和字符串方法详解
一、数组方法 数组方法是操作数组的核心工具,分为修改原数组和返回新数组两类。 1. 常用修改原数组的方法 方法参数返回值说明示例push...items新长度末尾添加元素arr.push(4) → [1,2,3,4]pop无删除的元素删除最后一个元素arr.pop() → 3(原数组变[1,…...

达梦数据库系列之Mysql项目迁移为达梦项目
达梦数据库系列之Mysql项目迁移为达梦项目 1 达梦数据库安装及MySql数据迁移2 SpringBoot项目迁移2.1 驱动包引入2.2 驱动类配置2.3 数据源配置2.4 flowable迁移2.4.1 异常问题2.4.2 解决 3 迁移常见问题3.1 不是 GROUP BY 表达式3.1.1 dm.ini 开启Mysql兼容模式3.1.2 修改动态…...

10个实用IntelliJ IDEA插件
精心整理了最新的面试资料和简历模板,有需要的可以自行获取 点击前往百度网盘获取 点击前往夸克网盘获取 以下是为提升开发效率推荐的10个实用IntelliJ IDEA插件,涵盖代码质量、效率工具及热门框架支持: 一、代码质量与规范 SonarLint 实时…...

10分钟从零开始搭建机器人管理系统(飞算AI)
1. 安装插件 https://www.feisuanyz.com/ 2. Intellij IDEA中运行 创建一个BS架构的机器人远程操控系统,具备机器人状态及位置实时更新,可以实现机器人远程遥控,可以对机器人工作日志进行统计分析,以及其它管理系统的常用功能3…...

[自动驾驶-传感器融合] 多激光雷达的外参标定
文章目录 引言外参标定原理ICP匹配示例参考文献 引言 多激光雷达系统通常用于自动驾驶或机器人,每个雷达的位置和姿态不同,需要将它们的数据统一到同一个坐标系下。多激光雷达外参标定的核心目标是通过计算不同雷达坐标系之间的刚性变换关系(…...

怎么让呼叫中心支持高并发
基于FreeSWITCH的呼叫中心系统并发性能优化指南 在呼叫中心系统建设中,高并发处理能力是衡量系统稳定性和效率的核心指标。作为开源软交换平台的代表,FreeSWITCH凭借其线程模型和模块化架构,天然适合高并发场景。然而,实际应用中仍…...

Elasticsearch简单学习
1、依赖的导入 <!--ES依赖--> <dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifactId> </dependency>2、客户端链接 RestHighLevelClient client new RestHigh…...

就像BGP中的AS_PATH一样,无论路途多远,我愿意陪你一起走——基于华为ENSP的BGP的路由负载均衡及过滤深入浅出
本篇技术博文摘要 🌟 本文内容涵盖了BGP负载均衡的基本概念、配置技巧和在实际网络中的应用,包括如何在华为ENSP上实现负载均衡和路由过滤。通过配置BGP的前缀列表、ACL以及路由过滤策略,可以实现网络流量的精确控制和优化,提高网…...

valgrind 检测多线程 bug,检测 并发 bug concurrent bug parallel bug
valgrind --toolhelgrind ./your_program 如果检测的对象是大型程序,可以设定仅在某些函数中开启 valgrind 的检测: Valgrind 提供了一些客户请求(client requests),可以在代码中插入特定的宏来控制 Valgrind 的行为。…...

游戏引擎学习第135天
仓库:https://gitee.com/mrxiao_com/2d_game_3 回顾 game_asset.cpp 的创建 在开发过程中,不使用任何现成的游戏引擎或第三方库,而是直接基于 Windows 进行开发,因为 Windows 目前仍然是游戏的标准平台,因此首先在这个环境中进行…...

异步操作返回原始上下文
是什么? 在讨论同步上下文执行回调的概念时,我们首先需要了解一些基本概念:同步与异步操作、上下文以及回调函数。 同步与异步操作: 同步操作是指代码按照顺序依次执行,每个操作必须等待前一个操作完成才能开始。这便…...

区块链中的数字签名:安全性与可信度的核心
数字签名是区块链技术的信任基石,它像区块链世界的身份证和防伪标签,确保每一笔交易的真实性、完整性和不可抵赖性。本文会用通俗的语言,带你彻底搞懂区块链中的数字签名! 文章目录 1. 数字签名是什么?从现实世界到区块…...

vulnhub渗透日记23:bulldog
声明 文中涉及操作均来自靶机虚拟环境,禁止用于真实环境,任何未经授权的渗透测试都是违法行为! 开搞 首先nmap扫描目标机开放端口和服务 访问80端口 扫目录撒 发现登录口 点击web-shell提示登录后才能使用 /dev/下面查看网页源码发现村咋h…...

macOS - 使用 tmux
文章目录 安装 tmux使用更多快捷键说明 安装 tmux brew install tmux使用 在终端输入 tmux 进入 tmux 界面,然后 输入 Control Option B 进入交互模式 输入 % 左右分栏," 上下分割 上一个窗格:{,下一个:} PS…...

Armbian: 轻量级 ARM 设备专用 Linux 发行版全面解析
引言 在嵌入式开发和物联网(IoT)领域,选择合适的操作系统至关重要。对于 Raspberry Pi、Orange Pi、Banana Pi 以及 Rockchip、Amlogic、Allwinner 等 ARM 平台上的单板计算机(SBC),一个高效、轻量级并且易…...