文章目录
- 泛型解决了什么问题?
- 泛型概念
- 泛型类
- 泛型方法
- 泛型接约束
- 泛型的优势
- 练习
泛型解决了什么问题?
在没有泛型时,如果我们想为不同类型(int和string)实现相同的逻辑,可能需要写多个重复的类或方法。例如,一个存储整数的容器和一个存储字符串类型的容器,他们的逻辑相同但类型不同。泛型通过类型参数化解决了这个问题——让你在定义类、方法或接口时使用占位符(比如 T)。
泛型概念
泛型允许你在定义类、接口或方法时使用类型参数。这些类型参数可以在实际使用时被指定为任何类型。常见的泛型用途包括集合类(如 List)以及方法和类的通用实现。
泛型类
个泛型类定义允许你使用类型参数
internal class Class1<T>
{
private T value;
public void SetValue(T value)
{
this.value = value;
}
public T GetValue()
{
return this.value;
}
}
T是一个类型参数,可以在创建Class1类的实例时指定具体类型,如int,string等:
Class1<int> intClass = new Class1<int>();
intClass.SetValue(10);
Console.WriteLine(intClass.GetValue());
Class1<string> stringClass = new Class1<string>();
stringClass.SetValue("hello world");
Console.WriteLine(stringClass.GetValue());
泛型方法
泛型方法是可以在方法定义中使用类型参数的普通方法。它与泛型类类似,但是只作用域该方法范围内的参数和返回类型
public class Printer
{
public void Print<T>(T value)
{
Console.WriteLine(value);
}
}
在调用时,你可以传入任何类型:
Printer printer = new Printer();
printer.Print(123);
printer.Print("liu wei");
泛型接约束
泛型接口定义了一个可以与不同类型一起使用的接口。例如,IEnumerable 接口就是泛型接口,它用于表示一个可枚举的集合:
为了让泛型更安全,可以限制类型参数 T 的允许范围。常见的约束有:
where T : struct → T 必须是值类型(如 int, double)
where T : class → T 必须是引用类型(如 string, 类)
where T : new() → T 必须有无参构造函数
where T : 接口名 → T 必须实现某个接口
只允许值类型
public class ValueContent<T> where T : struct
{
private T Value { get; set; }
}
//正确
ValueContent<int> valueContent = new ValueContent<int>();
//错误
ValueContent<string> valueContent = new ValueContent<string>();
泛型的优势
避免重复代码:只需写一次逻辑,适用于所有类型。
类型安全:不再需要强制转换(如 object 到 int)。
性能优化:避免装箱(Boxing)和拆箱(Unboxing)。
练习
//比较两个数的大小
public class Class2
{
public static T Max<T>(T a, T b) where T : IComparable<T>
{
return a.CompareTo(b) > 0 ? a : b;
}
}
//交换两个数的变量值
public void Swap<T>(T a,T b)
{
T temp = a;
a = b;
b = a;
}
public class Logger<T>
{
private List<string> _logs = new List<string>();
// 记录一条日志(包含时间和类型信息)
public void Log(T message)
{
string logEntry = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] [{typeof(T).Name}] {message}";
_logs.Add(logEntry);
}
public void checkLog()
{
foreach(var log in _logs)
{
Console.WriteLine(log);
}
}
}
var intLogger = new Logger<int>();
intLogger.Log(42);
intLogger.Log(100);
var stringLogger = new Logger<string>();
stringLogger.Log("Error occurred");
stringLogger.Log("Operation completed");
intLogger.checkLog();
stringLogger.checkLog();
[2025-02-22 11:19:07] [Int32] 42
[2025-02-22 11:19:07] [Int32] 100
[2025-02-22 11:19:07] [String] Error occurred
[2025-02-22 11:19:07] [String] Operation completed