泛型
1. 概述
泛型(Generics)是C#中一个强大的特性,允许你编写可以处理多种数据类型的代码,而不需要为每种数据类型编写单独的实现。泛型可以提高代码的重用性、类型安全性和性能。
1.1 为什么需要泛型?
在泛型出现之前,开发者通常使用object类型来处理不同类型的数据。然而,这种方式存在以下问题:
- 类型安全问题:使用
object类型时,编译器无法在编译时检查类型,容易导致运行时错误。 - 性能问题:将值类型转换为
object类型(装箱)和从object类型转换回值类型(拆箱)会导致性能损失。
泛型的引入解决了这些问题,使得代码更加安全、高效。
2. 泛型类
泛型类是使用泛型参数定义的类。泛型参数用尖括号<>括起来,通常用单个大写字母表示,如T。
2.1 定义泛型类
public class GenericClass<T>
{
private T _value;
public GenericClass(T value)
{
_value = value;
}
public T GetValue()
{
return _value;
}
public void SetValue(T value)
{
_value = value;
}
}
2.2 使用泛型类
class Program
{
static void Main()
{
// 使用泛型类存储整数
GenericClass<int> intContainer = new GenericClass<int>(10);
Console.WriteLine(intContainer.GetValue()); // 输出: 10
// 使用泛型类存储字符串
GenericClass<string> stringContainer = new GenericClass<string>("Hello");
Console.WriteLine(stringContainer.GetValue()); // 输出: Hello
}
}
2.3 泛型类的优势
- 类型安全:编译器会在编译时检查类型,确保类型一致性。
- 代码重用:相同的逻辑可以应用于不同的数据类型。
3. 泛型方法
泛型方法是在方法级别使用泛型参数。泛型方法可以在非泛型类中定义。
3.1 定义泛型方法
public class GenericMethodExample
{
public static void Swap<T>(ref T a, ref T b)
{
T temp = a;
a = b;
b = temp;
}
}
3.2 使用泛型方法
class Program
{
static void Main()
{
int x = 5, y = 10;
GenericMethodExample.Swap(ref x, ref y);
Console.WriteLine($"x: {x}, y: {y}"); // 输出: x: 10, y: 5
string s1 = "Hello", s2 = "World";
GenericMethodExample.Swap(ref s1, ref s2);
Console.WriteLine($"s1: {s1}, s2: {s2}"); // 输出: s1: World, s2: Hello
}
}
3.3 泛型方法的优势
- 灵活性:可以在不改变方法签名的情况下处理不同类型的数据。
- 类型安全:编译器会在编译时检查类型,确保类型一致性。
4. 泛型约束
泛型约束(Generic Constraints)用于限制泛型参数的类型。通过约束,可以确保泛型参数满足特定的条件。
4.1 常见的泛型约束
where T : class:T必须是引用类型。where T : struct:T必须是值类型。where T : new():T必须有一个无参构造函数。where T : BaseClass:T必须是BaseClass或其子类。where T : IInterface:T必须实现IInterface接口。
4.2 示例:使用泛型约束
public class GenericConstraintExample<T> where T : new()
{
public T CreateInstance()
{
return new T();
}
}
class Program
{
static void Main()
{
GenericConstraintExample<MyClass> example = new GenericConstraintExample<MyClass>();
MyClass instance = example.CreateInstance();
Console.WriteLine(instance.GetType().Name); // 输出: MyClass
}
}
public class MyClass
{
public MyClass() { }
}
4.3 泛型约束的优势
- 类型安全:确保泛型参数满足特定的条件,避免运行时错误。
- 灵活性:可以根据需要添加多个约束,进一步限制泛型参数的类型。
5. 实践练习
5.1 练习1:实现一个泛型栈
实现一个泛型栈(Stack)类,支持压入(Push)、弹出(Pop)和查看栈顶元素(Peek)操作。
public class GenericStack<T>
{
private List<T> _items = new List<T>();
public void Push(T item)
{
_items.Add(item);
}
public T Pop()
{
if (_items.Count == 0)
{
throw new InvalidOperationException("Stack is empty");
}
T item = _items[_items.Count - 1];
_items.RemoveAt(_items.Count - 1);
return item;
}
public T Peek()
{
if (_items.Count == 0)
{
throw new InvalidOperationException("Stack is empty");
}
return _items[_items.Count - 1];
}
public int Count => _items.Count;
}
5.2 练习2:使用泛型方法实现排序
实现一个泛型方法,对数组进行排序。可以使用Array.Sort方法。
public class GenericSortExample
{
public static void Sort<T>(T[] array) where T : IComparable<T>
{
Array.Sort(array);
}
}
class Program
{
static void Main()
{
int[] numbers = { 3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5 };
GenericSortExample.Sort(numbers);
Console.WriteLine(string.Join(", ", numbers)); // 输出: 1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 9
string[] words = { "banana", "apple", "cherry", "date" };
GenericSortExample.Sort(words);
Console.WriteLine(string.Join(", ", words)); // 输出: apple, banana, cherry, date
}
}
6. 总结
泛型是C#中一个非常重要的特性,它允许你编写灵活、类型安全的代码。通过泛型类、泛型方法和泛型约束,你可以大大提高代码的重用性和可维护性。
6.1 关键点回顾
- 泛型类:使用泛型参数定义类,提高代码重用性和类型安全性。
- 泛型方法:在方法级别使用泛型参数,增加代码的灵活性。
- 泛型约束:限制泛型参数的类型,确保类型安全。
6.2 下一步学习
- 委托和事件:学习如何使用委托和事件处理程序。
- LINQ:掌握语言集成查询(LINQ),用于数据查询和操作。
- 异步编程:了解如何使用
async和await进行异步编程。
通过不断练习和实践,你将能够熟练掌握泛型,并将其应用于实际项目中。