C#基础篇(11)泛型类与泛型方法详解
一、C# 中的泛型类详解
泛型类是 C# 中一种强大的特性,它允许你定义可以使用不同类型的类,而无需为每种类型编写单独的类。泛型类通过类型参数实现这一功能,提高了代码的重用性、类型安全性和性能。
1. 泛型类的基本语法
public class GenericClass<T>
{// T 是类型参数,可以在类中作为类型使用private T data;public GenericClass(T value){data = value;}public T GetData(){return data;}
}
2. 泛型类的使用
// 使用int类型实例化泛型类
GenericClass<int> intGeneric = new GenericClass<int>(10);
int intValue = intGeneric.GetData();// 使用string类型实例化泛型类
GenericClass<string> stringGeneric = new GenericClass<string>("Hello");
string stringValue = stringGeneric.GetData();
3. 泛型类的优势
- 类型安全:编译时检查类型,避免运行时类型转换错误
- 代码重用:一套代码可以用于多种数据类型
- 性能优化:避免了装箱和拆箱操作(对于值类型)
- 减少强制转换:代码更简洁,不需要频繁的类型转换
4. 多类型参数的泛型类
泛型类可以有多个类型参数:
public class Pair<TKey, TValue>
{public TKey Key { get; set; }public TValue Value { get; set; }public Pair(TKey key, TValue value){Key = key;Value = value;}
}// 使用示例
var pair = new Pair<int, string>(1, "One");
5. 泛型约束
可以为类型参数添加约束,限制可以使用的类型:
约束类型 | 语法 | 描述 |
---|---|---|
类约束 | where T : class | T必须是引用类型 |
结构约束 | where T : struct | T必须是值类型(Nullable除外) |
基类约束 | where T : BaseClass | T必须继承自BaseClass |
接口约束 | where T : IInterface | T必须实现IInterface |
无参数构造函数约束 | where T : new() | T必须有无参构造函数 |
裸类型约束 | where T : U | T必须继承自或实现U |
示例:
public class GenericClass<T> where T : IComparable, new()
{private T data;public GenericClass(){data = new T(); // 需要new()约束}public int CompareTo(T other){return data.CompareTo(other); // 需要IComparable约束}
}
6. 泛型类的继承
泛型类可以继承自其他泛型或非泛型类:
public class BaseClass<T>
{// 基类实现
}// 派生类可以是具体类型
public class DerivedClass : BaseClass<int>
{// 实现
}// 派生类也可以是泛型类
public class DerivedGenericClass<T> : BaseClass<T>
{// 实现
}// 派生类可以添加自己的类型参数
public class DerivedMultiClass<T, U> : BaseClass<T>
{// 实现
}
7. 静态成员
泛型类的静态成员是针对每个封闭类型独立的:
public class GenericClass<T>
{public static int Count { get; set; }
}// 使用示例
GenericClass<int>.Count = 10;
GenericClass<string>.Count = 20;Console.WriteLine(GenericClass<int>.Count); // 输出10
Console.WriteLine(GenericClass<string>.Count); // 输出20
8. 泛型类与反射
可以使用反射获取泛型类型信息:
Type genericType = typeof(List<>);
Type constructedType = genericType.MakeGenericType(typeof(int));
object list = Activator.CreateInstance(constructedType);
总结
C# 泛型类是一种强大的语言特性,它通过类型参数化实现了代码的高度重用,同时保持了类型安全和性能。合理使用泛型类可以:
- 减少代码重复
- 提高类型安全性
- 改善性能(特别是对于值类型)
- 创建更灵活、更通用的数据结构
在设计泛型类时,应当考虑类型约束、命名规范、文档注释等因素,以确保代码的可读性和可维护性。
二、C# 中的泛型方法详解
泛型方法是 C# 泛型编程的核心组成部分,它允许你定义可以操作多种类型的方法,而无需为每种类型编写单独的方法。泛型方法提供了类型安全和代码重用的双重优势。
1. 泛型方法的基本语法
// 泛型方法定义
public T GenericMethod<T>(T parameter)
{// 方法体return parameter;
}// 使用示例
int result = GenericMethod<int>(5); // 显式指定类型
string text = GenericMethod("Hello"); // 类型推断
核心特点:
- 类型参数:使用尖括号
<T>
声明类型参数 - 类型安全:编译时类型检查
- 代码重用:同一方法可用于多种类型
- 性能优势:避免值类型的装箱拆箱操作
2. 泛型方法的定义方式
1. 普通类中的泛型方法
public class Utility
{public void Print<T>(T value){Console.WriteLine($"Type: {typeof(T)}, Value: {value}");}// 多类型参数public TResult Convert<TInput, TResult>(TInput input){return (TResult)Convert.ChangeType(input, typeof(TResult));}
}
2. 泛型类中的泛型方法
public class Repository<TEntity>
{// 类类型参数TEntity与方法类型参数T是独立的public T Execute<T>(Func<TEntity, T> selector){// 实现...}
}
3. 静态类中的泛型方法
public static class MathUtils
{public static T Max<T>(T a, T b) where T : IComparable<T>{return a.CompareTo(b) > 0 ? a : b;}
}
4. 接口中的泛型方法
public interface IProcessor
{TResult Process<TInput, TResult>(TInput input);
}
3. 泛型方法的类型参数约束
约束可以限制可用于泛型方法的类型参数,提供更强的类型安全和功能支持。
常用约束类型
约束类型 | 语法示例 | 说明 |
---|---|---|
类约束 | where T : class | T必须是引用类型 |
结构约束 | where T : struct | T必须是值类型(Nullable除外) |
基类约束 | where T : BaseClass | T必须继承自BaseClass |
接口约束 | where T : IInterface | T必须实现IInterface |
无参构造函数约束 | where T : new() | T必须有无参构造函数 |
裸类型约束 | where T : U | T必须继承自或实现U |
约束组合示例
public T CreateAndCompare<T>(T value) where T : class, IComparable<T>, new()
{T newInstance = new T();return value.CompareTo(newInstance) > 0 ? value : newInstance;
}
4. 泛型方法的高级特性
1. 类型推断
C#编译器通常可以推断泛型方法的类型参数,无需显式指定:
// 不需要指定<int>,编译器从参数推断
int max = MathUtils.Max(5, 10);
2. 泛型方法与重载
泛型方法可以与非泛型方法重载:
public class Printer
{public void Print<T>(T value) { /* 泛型实现 */ }public void Print(int value) { /* 特定类型实现 */ }
}
调用时,编译器会优先选择最具体的匹配。
3. 递归泛型方法
泛型方法可以递归调用自身:
public static T[] BubbleSort<T>(T[] array) where T : IComparable<T>
{for (int i = 0; i < array.Length - 1; i++){if (array[i].CompareTo(array[i + 1]) > 0){T temp = array[i];array[i] = array[i + 1];array[i + 1] = temp;return BubbleSort(array); // 递归调用}}return array;
}
4. 协变和逆变(C# 4.0+)
使用in
和out
修饰符:
// 协变返回类型
public interface IFactory<out T>
{T Create();
}// 逆变参数
public interface IComparer<in T>
{int Compare(T x, T y);
}
5. 泛型方法与反射
可以通过反射调用泛型方法:
public class ReflectionExample
{public static void CallGenericMethod(){var method = typeof(Utility).GetMethod("Print");var genericMethod = method.MakeGenericMethod(typeof(int));genericMethod.Invoke(null, new object[] { 42 });}
}
总结
C# 泛型方法是强大的编程工具,它:
- 提高了代码的重用性和类型安全
- 消除了强制转换的需要
- 为值类型提供了更好的性能
- 使API设计更加灵活和表达力强
合理使用泛型方法可以显著提高代码质量,但也要注意避免过度复杂化。掌握泛型方法的使用是成为高级C#开发者的重要一步。