当前位置: 首页 > news >正文

C# 泛型

# 一、泛型方法中 <T> 的含义与作用
1. **<T> 表示类型参数**
T 是一个**占位符**,代表**任意一种数据类型**。
在方法定义时不确定具体类型,调用时才确定。
2. **T 可以是任意类型**
包括:
- 值类型:int、double、bool、char、struct
- 引用类型:string、类、数组、接口

、、、csharp

using System;

class Program
{
// 定义泛型方法,<T> 为类型占位符
public static void ShowInfo<T>(T data)
{
Console.WriteLine($"数据值:{data},数据类型:{typeof(T)}");
}

static void Main()
{
// 1. 值类型调用
ShowInfo<int>(100);
ShowInfo<double>(3.14);
ShowInfo<bool>(true);
ShowInfo<char>('A');

// 2. 引用类型调用
ShowInfo<string>("测试字符串");
ShowInfo<object>(new object());

// 编译器可自动推断类型,省略 <T>
ShowInfo(666);
ShowInfo("自动推断类型");

Console.ReadKey();
}
}


3. **类型推导机制**
调用泛型方法时,**编译器会根据传入参数自动推导 T 的类型**,
不需要手动写 <int> / <string>。
4. **泛型的核心优势**
一套代码,支持所有类型,**避免重复代码、避免类型转换、提高安全性**。

、、、csharp

using System;

class GenericDemo
{
// 泛型方法
public static void PrintData<T>(T value)
{
Console.WriteLine($"值:{value},类型:{typeof(T).Name}");
}

static void Main()
{
// 1. 类型推导:省略 <类型>,编译器自动识别
PrintData(100); // 自动推导 T = int
PrintData(3.14); // 自动推导 T = double
PrintData("Hello"); // 自动推导 T = string
PrintData(true); // 自动推导 T = bool

// 也可以手动指定类型,两种写法都合法
PrintData<string>("手动指定字符串类型");

// 对比:不用泛型,需要写多个重载方法,代码冗余
// public static void Print(int a){}
// public static void Print(double a){}
// public static void Print(string a){}

Console.ReadKey();
}
}


# 二、泛型的重要限制:未约束 T 不能直接使用 + 运算符
1. **未约束的泛型 T,编译器不知道它是什么类型**
不知道是否支持 `+`、`-`、`*`、`/` 等运算符。
2. **直接对 T 类型变量做数学运算会编译报错**
因为编译器无法验证运算是否合法。
3. **解决方式**
- 使用**泛型约束**
- 使用动态类型 dynamic
- 使用运算符重载或第三方库辅助
4. **核心结论(必背)**
**无约束的泛型 T 不能直接进行算术运算。**

、、、csharp

using System;

class Program
{
// 无约束泛型方法
public static void Calc<T>(T a, T b)
{
// 编译报错:无约束 T 不能直接使用 + 运算符
// T result = a + b;
}

// 方式1:使用 dynamic 绕过限制
public static void AddByDynamic<T>(T a, T b)
{
dynamic d1 = a;
dynamic d2 = b;
var res = d1 + d2;
Console.WriteLine($"运算结果:{res}");
}

static void Main()
{
AddByDynamic(10, 20);
AddByDynamic(3.14, 2.86);

Console.ReadKey();
}
}


# 三、方法重载优先级:固定类型方法 > 泛型方法
1. **同一个类中,普通方法(固定类型)与泛型方法可构成重载**
2. **重载匹配规则(考试必考)**
**精确匹配的普通方法 > 泛型方法**
传入 int → 优先调用 int 方法
传入 string → 优先调用 string 方法
无精确匹配时,才会调用泛型方法。
3. **为什么?**
普通方法是**明确类型**,泛型是**通用类型**,
编译器永远优先选择**最具体、最精确**的方法。
4. **必背结论**
**固定类型方法优先级 > 泛型方法。**

、、、csharp

using System;

class Test
{
// 普通 int 类型方法
public static void Show(int num)
{
Console.WriteLine("调用 int 普通方法:" + num);
}

// 普通 string 类型方法
public static void Show(string str)
{
Console.WriteLine("调用 string 普通方法:" + str);
}

// 泛型方法
public static void Show<T>(T data)
{
Console.WriteLine($"调用泛型方法,类型:{typeof(T).Name},值:{data}");
}

static void Main()
{
// 1. 精确匹配,优先执行对应普通方法
Show(100);
Show("C#");

// 2. 无对应普通方法,才会调用泛型方法
Show(3.14);
Show(true);

Console.ReadKey();
}
}


# 四、泛型类继承普通类(非泛型类)的规则
1. **泛型类可以继承非泛型(普通)类**
语法:`class GenericClass<T> : NormalClass`
2. **继承后,父类成员完全可用**
子类可以直接访问父类的字段、属性、方法。
3. **泛型参数 T 只作用于当前泛型类,不影响父类**
父类是普通类,与 T 无关。
T 只在子类内部生效。
4. **语法合法、使用广泛**
常用于:通用工具类、通用管理类、通用模型。
5. **核心结论**
**泛型类可以正常继承非泛型类,继承关系不受泛型影响。**

、、、csharp

using System;

// 非泛型父类(普通类)
class ParentClass
{
public string Name { get; set; }

public void SayHello()
{
Console.WriteLine("来自普通父类的方法:Hello");
}
}

// 泛型子类 继承 普通父类
class ChildClass<T> : ParentClass
{
// 泛型类独有的泛型成员
public T Data { get; set; }

public void ShowData()
{
Console.WriteLine($"泛型数据:{Data},类型:{typeof(T).Name}");
}
}

class Program
{
static void Main()
{
// 使用 int 作为泛型参数
ChildClass<int> obj1 = new ChildClass<int>();
// 调用父类属性和方法
obj1.Name = "测试1";
obj1.SayHello();
// 调用自身泛型成员
obj1.Data = 100;
obj1.ShowData();

Console.WriteLine("------------------");

// 使用 string 作为泛型参数
ChildClass<string> obj2 = new ChildClass<string>();
obj2.Name = "测试2";
obj2.SayHello();
obj2.Data = "泛型字符串";
obj2.ShowData();

Console.ReadKey();
}
}


# 五、四条知识点 终极精简背诵版(最适合记忆)
1. **<T> = 类型参数,调用时自动推导,支持任意类型。**
2. **无约束 T 不能直接运算,因为编译器不知道类型。**
3. **方法重载:普通固定类型方法 优先于 泛型方法。**
4. **泛型类可继承普通类,父类不受 T 影响,子类正常使用父类成员。**

http://www.jsqmd.com/news/918474/

相关文章:

  • Rusted PackFile Manager:全面战争MOD开发的终极效率工具完整教程
  • 为什么你的论文参考文献格式总是不对?3个GB/T 7714 BibTeX样式终极解决方案
  • IF=10.0!浙大博士一作再登柳叶刀子刊!
  • 如何快速修改暗黑破坏神2存档:5分钟掌握d2s-editor完整使用指南
  • 2026年徐州甲级写字楼集中区揭秘,锁定这三大板块
  • Linux权限进阶:从passwd命令到SUID/SGID,搞懂那些‘s’和‘t’到底怎么用
  • 187、运动控制中的行业应用:机械臂力控打磨
  • 如何告别图片格式烦恼?Save Image as Type让网页图片一键转换
  • 前端内存泄漏常见场景与排查
  • FanControl深度解析:Windows风扇控制从入门到精通的完整指南
  • Gemini产品需求文档标准模板(2024最新版V2.3·仅限头部AI团队内部流通)
  • Python 潮流周刊#152:编程智能体终于跨过质量门槛了?
  • GTA5线上小助手:免费开源工具帮你轻松称霸洛圣都终极指南
  • 【AI+房地产实战指南】:2024年最值得落地的7大智能整合场景与避坑清单
  • Gemini财务分析报告深度拆解(2024版审计底稿首次公开)
  • ARP 协议:网络世界里的“地址翻译官“
  • Kettle官网大变样?别慌!手把手教你找到最新9.3版本的下载入口(附Hadoop Shims获取指南)
  • 安徽工业无人机维修痛点难解?专业无人机维修培训方案认准乘云低空,无人机实操培训,无人机维修培训机构哪家强 - 品牌推荐师
  • 网盘直链下载助手:告别限速,解锁九大网盘高速下载方案
  • SBM-20-1盖革管3D打印端盖制作:从零打造专业级辐射探测器接口
  • YOLOv11古生物化石研究沙虎鲨牙齿目标检测数据集-280张-shark-teeth-1
  • 为什么你的芯片离不开它?聊聊带隙基准在LDO、ADC里的那些事儿
  • GTWR与GWR模型怎么选?结合房价案例聊聊时空权重的实际影响
  • 2026AI漫剧创作深度测评:如何为你的创作需求匹配最佳方案? - 速递信息
  • 如何让老款Mac重获新生:OpenCore Legacy Patcher终极升级指南
  • 189、运动控制中的行业应用:医疗设备(手术机器人)
  • 英雄联盟R3nzSkin换肤工具实战指南:国服安全自定义皮肤完整方案
  • yuzu模拟器架构深度解析:从Switch硬件仿真到跨平台渲染优化
  • 如何快速搭建免费的个人天气API:Open-Meteo终极指南
  • 告别信号‘自消’:深入浅出聊聊波束形成中协方差矩阵重建与对角加载的‘组合拳’