C# 泛型generic的简单理解

本文介绍了C#中的泛型机制,这是从C# 2.0开始引入的新特性,用于提高代码复用性和类型安全性。通过使用类型参数T,可以在不指定具体类型的情况下设计类和方法,直到客户端代码实例化时才确定具体类型,从而避免了装箱和拆箱带来的性能开销。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

根据MSDN的一段话:泛型(generic)是C#语言2.0和通用语言运行时(CLR)的一个新特性。泛型为.NET框架引入了类型参数(type parameters)的概念。类型参数使得设计类和方法时,不必确定一个或多个具体参数,其的具体参数可延迟到客户代码中声明、实现。使用泛型的类型参数T,避免运行时类型转换或装箱操作的代价和风险。

MSDN:《Microsoft Developer Network》(简称MSDN),是微软的一个期刊产品,专门介绍各种编程技巧。

generic:一般的,通用的,广泛的。(泛型:通用的,暂时没有指明类型,在创建对象时指明类型的一种技术)

举例:

定义一个类似堆栈存取的类A,在主方法里进行操作。A中定义的是int数组

可以看到,这里可以进行int类型数据的存取操作,但是如果是float类型呢,或者string类型呢?我们可以想到把int换成object(代码略)。那么,主方法中put时,用到了装箱,后面做加减(或其他)时用到了拆箱,如果数据量比较大,则就要付出比较大的代价和风险。那怎么办呢?-----用泛型

泛型写法:在类名称的后面用<T>表示,T表示一种暂未指明的类型,相关的地方用T表示,在类创建对象时才指明数据类型,这样,就不会产生装箱拆箱操作,大大提高了效率和安全性。如:


在C#的基础类库中,已经有很多泛型,如:


<think>我们被要求解释C#(Generic)的作用,并提供代码示例和解释。然后按照格式提出相关问题。 C#中一个强大的特性,它允许我们编写可以适用于多种数据类的类、方法、接口等,而无需为每种类单独编写代码。的主要作用是提高代码的重用性、类安全性和性能。 作用: 1. 代码重用:编写一次,适用于多种类。 2. 类安全:在编译时进行类检查,避免运行时类转换错误。 3. 性能:避免装箱和拆箱操作(对于值类),提高性能。 常见应用:类、方法、接口、委托。 下面通过几个示例来展示的使用。</think>### C#(Generic)的作用详解 C#中的核心特性,允许你编写可重用的代码组件,这些组件可以处理不同类的数据,而无需为每种类单独实现。的主要作用是提供**类安全**和**代码重用**,同时避免装箱拆箱带来的性能损耗。 #### 的六大核心作用 1. **类安全性** - 编译时类检查,避免运行时类转换错误 - 消除强制类转换的需要 2. **代码重用** - 单个实现可处理多种数据类 - 减少重复代码 3. **性能优化** - 避免值类的装箱拆箱操作 - 直接操作原始数据类 4. **集合安全性** - 创建类安全的集合(如`List<T>`) - 防止添加错误类元素 5. **算法通用化** - 编写与数据类无关的通用算法 - 例如排序、搜索等算法 6. **约束灵活性** - 通过约束指定类能力(如`where T : IComparable`) - 平衡灵活性与安全性 --- ### 代码示例 #### 1. 基本类示例 ```csharp using System; // 类定义 public class Box<T> { private T content; public Box(T initialContent) { content = initialContent; } public T GetContent() { return content; } public void UpdateContent(T newContent) { content = newContent; } } class Program { static void Main() { // 整数盒子 Box<int> intBox = new Box<int>(42); Console.WriteLine($"整数内容: {intBox.GetContent()}"); // 字符串盒子 Box<string> strBox = new Box<string>("Hello Generics"); Console.WriteLine($"字符串内容: {strBox.GetContent()}"); // 自定义类盒子 Box<DateTime> dateBox = new Box<DateTime>(DateTime.Now); Console.WriteLine($"日期内容: {dateBox.GetContent()}"); } } ``` **解释**: - `Box<T>`是类,`T`是类参数占位符 - 创建实例时指定具体类(如`Box<int>`) - 同一类可安全处理不同类数据 #### 2. 方法示例 ```csharp using System; class GenericMethods { // 方法:交换两个值 public static void Swap<T>(ref T a, ref T b) { T temp = a; a = b; b = temp; } // 方法:查找最大值(带约束) public static T Max<T>(T a, T b) where T : IComparable<T> { return a.CompareTo(b) > 0 ? a : b; } } class Program { static void Main() { // 交换整数 int x = 5, y = 10; Console.WriteLine($"交换前: x={x}, y={y}"); GenericMethods.Swap(ref x, ref y); Console.WriteLine($"交换后: x={x}, y={y}"); // 交换字符串 string s1 = "Hello", s2 = "World"; Console.WriteLine($"交换前: s1={s1}, s2={s2}"); GenericMethods.Swap(ref s1, ref s2); Console.WriteLine($"交换后: s1={s1}, s2={s2}"); // 查找最大值 double maxDouble = GenericMethods.Max(3.14, 2.71); Console.WriteLine($"较大值: {maxDouble}"); string maxString = GenericMethods.Max("Apple", "Banana"); Console.WriteLine($"字母顺序靠后: {maxString}"); } } ``` **解释**: - `Swap<T>`方法可交换任意类变量 - `Max<T>`方法使用约束`where T : IComparable<T>`确保类可比较 - 方法可直接调用,编译器推断类 #### 3. 约束示例 ```csharp using System; public interface IIdentifiable { int Id { get; } } public class Product : IIdentifiable { public int Id { get; set; } public string Name { get; set; } } public class Repository<T> where T : IIdentifiable { private List<T> items = new List<T>(); public void Add(T item) { items.Add(item); } public T GetById(int id) { return items.FirstOrDefault(i => i.Id == id); } } class Program { static void Main() { Repository<Product> productRepo = new Repository<Product>(); productRepo.Add(new Product { Id = 1, Name = "Laptop" }); productRepo.Add(new Product { Id = 2, Name = "Phone" }); Product found = productRepo.GetById(2); Console.WriteLine($"找到产品: {found?.Name}"); // 以下代码会编译错误,因为string不满足IIdentifiable约束 // Repository<string> invalidRepo = new Repository<string>(); } } ``` **解释**: - `where T : IIdentifiable`约束确保`T`实现指定接口 - 在`GetById`方法中可直接访问`Id`属性 - 尝试使用不满足约束的类会导致编译错误 --- ### 与Object的性能对比 ```csharp using System; using System.Collections.Generic; using System.Diagnostics; class PerformanceTest { const int Iterations = 10000000; static void TestGenericList() { List<int> list = new List<int>(); var sw = Stopwatch.StartNew(); for (int i = 0; i < Iterations; i++) { list.Add(i); int value = list[0]; list.RemoveAt(0); } sw.Stop(); Console.WriteLine($"List耗时: {sw.ElapsedMilliseconds}ms"); } static void TestArrayList() { ArrayList list = new ArrayList(); var sw = Stopwatch.StartNew(); for (int i = 0; i < Iterations; i++) { list.Add(i); // 装箱发生 int value = (int)list[0]; // 拆箱发生 list.RemoveAt(0); } sw.Stop(); Console.WriteLine($"ArrayList耗时: {sw.ElapsedMilliseconds}ms"); } static void Main() { TestGenericList(); TestArrayList(); } } ``` **典输出**: ``` List耗时: 520ms ArrayList耗时: 2450ms ``` **性能差异解释**: 1. **装箱拆箱开销**:`ArrayList`存储`object`类,值类需要装箱(内存分配)和拆箱(类转换) 2. **类安全检查**:在编译时完成类检查,`ArrayList`需要运行时检查 3. **内存效率**:直接使用值类,避免额外内存分配 --- ### 使用最佳实践 1. **优先使用集合**:`List<T>`替代`ArrayList` 2. **合理使用约束**:平衡灵活性与安全性 3. **避免过度化**:只在真正需要通用性的地方使用 4. **考虑协变逆变**:使用`in/out`关键字处理继承关系 5. **命名约定**:单字母类参数(T, K, V)或多字母描述性名称(TKey, TValue) ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值