1. 为什么需要掌握C#泛型与结构体
十年前我刚接触C#时,曾在一个工业控制项目中因为不理解泛型而写了大量重复代码。当时需要处理来自不同传感器的数据包——温度传感器返回double,压力传感器返回float,而光电传感器需要处理自定义的Measurement结构体。如果当时能深入理解泛型,至少能减少40%的代码量。
泛型(Generics)是C# 2.0引入的核心特性,它允许我们编写可以与任何数据类型一起工作而无需重复的类和方法。想象一下你有个工具箱,泛型就是给这个工具箱装上可更换的模具——同一套工具能处理不同形状的零件。
结构体(struct)则是轻量级的数据容器,特别适合表示简单的数据结构。在嵌入式通信协议解析中,我常用结构体来映射硬件寄存器布局。比如解析Modbus协议时,一个结构体就能清晰表示保持寄存器的内存布局:
csharp复制public struct ModbusRegister
{
public ushort Address;
public ushort Value;
public DateTime Timestamp;
}
枚举(enum)则让代码更易读。上周review同事代码时看到if(status == 2),花了十分钟才明白这是表示"报警状态"。如果用枚举AlarmStatus.Triggered,可读性立刻提升。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 泛型深度解析与实战技巧
2.1 泛型类型约束的四种玩法
泛型约束告诉编译器:"这个类型参数T必须满足这些条件"。最常见的约束包括:
csharp复制// 1. 值类型约束
public class ValueContainer<T> where T : struct {...}
// 2. 引用类型约束
public class ReferenceContainer<T> where T : class {...}
// 3. 构造函数约束
public class Factory<T> where T : new() {...}
// 4. 接口约束
public class Processor<T> where T : IComparable {...}
在开发数据缓存系统时,我曾用接口约束确保所有缓存项都实现IDisposable:
csharp复制public class Cache<T> where T : IDisposable
{
private List<T> _items = new List<T>();
~Cache() {
foreach(var item in _items)
item.Dispose();
}
}
2.2 泛型方法中的类型推断妙用
编译器能根据传入参数自动推断类型参数,这让代码更简洁:
csharp复制// 显式指定类型
var result1 = Convert<int>("123");
// 类型推断
var result2 = Convert("123"); // 自动推断为int
public T Convert<T>(string input) {...}
但在处理数值转换时要小心。有次我写Convert<T>("1.23"),当T为int时直接抛出异常。后来我增加了类型检查:
csharp复制public T SafeConvert<T>(string input)
{
if(typeof(T) == typeof(int) && input.Contains('.'))
throw new InvalidCastException("小数不能转为整数");
// ...
}
2.3 泛型性能优化实践
泛型在性能上比object装箱/拆箱快得多。用BenchmarkDotNet测试:
| 方法 | 均值 | 内存分配 |
|---|---|---|
| 装箱List | 112ns | 32B |
| 泛型List | 38ns | 0B |
在实时数据处理系统中,这个差异会被放大。我曾优化过一个气象数据采集系统,将ArrayList改为List<WeatherData>后,CPU使用率下降了15%。
3. 结构体的正确打开方式
3.1 结构体vs类的七个关键区别
- 内存分配:结构体在栈上(除非被装箱),类在堆上
- *默认值
