C Sharp 泛型
外观
C#泛型[编辑 | 编辑源代码]
介绍[编辑 | 编辑源代码]
泛型(Generics)是C#语言中一项强大的特性,允许开发者编写可重用的、类型安全的代码,而无需为每种数据类型重复编写相同的逻辑。泛型通过使用类型参数(Type Parameters)来实现这一目标,使得类、接口、方法等可以在定义时不指定具体类型,而在使用时再确定类型。
泛型的主要优点包括:
- 类型安全:编译时进行类型检查,避免运行时类型转换错误。
- 代码重用:同一套逻辑可以应用于多种数据类型。
- 性能优化:避免装箱和拆箱操作(对于值类型)。
基本语法[编辑 | 编辑源代码]
泛型通常通过尖括号 `<T>` 来声明类型参数,其中 `T` 是类型参数的名称(可以是任何有效的标识符)。
泛型类[编辑 | 编辑源代码]
以下是一个简单的泛型类示例:
public class GenericList<T>
{
private T[] items;
private int count = 0;
public GenericList(int capacity)
{
items = new T[capacity];
}
public void Add(T item)
{
items[count++] = item;
}
public T GetItem(int index)
{
return items[index];
}
}
使用泛型类[编辑 | 编辑源代码]
GenericList<int> intList = new GenericList<int>(5);
intList.Add(10);
intList.Add(20);
Console.WriteLine(intList.GetItem(0)); // 输出: 10
GenericList<string> stringList = new GenericList<string>(3);
stringList.Add("Hello");
stringList.Add("World");
Console.WriteLine(stringList.GetItem(1)); // 输出: World
泛型约束[编辑 | 编辑源代码]
泛型可以通过约束(Constraints)限制类型参数的范围,以确保类型参数符合特定条件。常见的约束包括:
- `where T : struct` - T必须是值类型。
- `where T : class` - T必须是引用类型。
- `where T : new()` - T必须有无参构造函数。
- `where T : BaseClass` - T必须继承自 `BaseClass`。
- `where T : InterfaceName` - T必须实现 `InterfaceName` 接口。
示例:泛型约束[编辑 | 编辑源代码]
public class GenericCalculator<T> where T : IComparable<T>
{
public T Max(T a, T b)
{
return a.CompareTo(b) > 0 ? a : b;
}
}
泛型方法[编辑 | 编辑源代码]
泛型方法允许在方法级别使用类型参数,而不需要整个类都是泛型的。
public static void Swap<T>(ref T a, ref T b)
{
T temp = a;
a = b;
b = temp;
}
调用泛型方法[编辑 | 编辑源代码]
int x = 5, y = 10;
Swap(ref x, ref y);
Console.WriteLine($"x = {x}, y = {y}"); // 输出: x = 10, y = 5
string s1 = "Hello", s2 = "World";
Swap(ref s1, ref s2);
Console.WriteLine($"s1 = {s1}, s2 = {s2}"); // 输出: s1 = World, s2 = Hello
泛型接口[编辑 | 编辑源代码]
泛型接口允许定义通用的接口契约,适用于多种类型。
public interface IRepository<T>
{
void Add(T entity);
T GetById(int id);
IEnumerable<T> GetAll();
}
实际应用案例[编辑 | 编辑源代码]
案例1:通用数据存储[编辑 | 编辑源代码]
泛型常用于实现数据存储结构,如 `List<T>`、`Dictionary<TKey, TValue>` 等。
List<int> numbers = new List<int> { 1, 2, 3 };
Dictionary<string, int> ages = new Dictionary<string, int>
{
{ "Alice", 25 },
{ "Bob", 30 }
};
案例2:泛型工厂模式[编辑 | 编辑源代码]
泛型可以用于实现工厂模式,动态创建不同类型的对象。
public class Factory<T> where T : new()
{
public T CreateInstance()
{
return new T();
}
}
泛型与性能[编辑 | 编辑源代码]
泛型在运行时不会产生额外的性能开销,因为C#编译器会为每个不同的值类型生成特定的代码(称为特化),而对于引用类型则共享同一份代码。
性能对比[编辑 | 编辑源代码]
方法 | 性能影响 |
---|---|
需要装箱和拆箱,性能较差 | |
无装箱/拆箱,性能更优 |
常见问题[编辑 | 编辑源代码]
1. 泛型与 `object` 的区别[编辑 | 编辑源代码]
- 泛型是类型安全的,而 `object` 需要强制类型转换。
- 泛型避免了装箱和拆箱操作(对于值类型)。
2. 泛型能否用于静态成员?[编辑 | 编辑源代码]
静态成员可以使用泛型类型参数,但静态成员本身不能是泛型的(除非在泛型类中)。
总结[编辑 | 编辑源代码]
泛型是C#中一项强大的特性,能够提高代码的复用性、类型安全性和性能。通过泛型类、泛型方法、泛型接口以及约束,开发者可以编写更加灵活和高效的代码。
进一步学习[编辑 | 编辑源代码]
- 泛型集合(`List<T>`、`Dictionary<TKey, TValue>`)
- 协变和逆变(`in` 和 `out` 关键字)
- 泛型委托(`Action<T>`、`Func<T>`)