什么是泛型,C#泛型详解
泛型实质上就是使程序员定义安全的类型。
在没有出现泛型之前,C# 提供了对 Object 的引用“任意化”操作。但这种任意化操作在执行某些强制类型转换时,有的错误也许不会被编译器捕捉,而在运行后出现异常。由此可见,强制类型转换存在安全隐患,所以 C# 提供了泛型机制。
本节就带着大家详细了解 C# 的泛型机制。
例如,下面代码定义了 3 个方法,分别用来获取 int、double 和 bool 类型的原始类型。
类型参数 T 的命名准则如下。
1) 使用描述性名称命名泛型类型参数,除非单个字母名称完全可以让人了解它表示的含义。例如,使用代表一定意义的单词作为类型参数T的名称,代码如下。
2) 将T作为描述性类型参数名的前缀。例如,使用T作为类型参数名的前缀,代码如下:
例如,定义一个泛型方法,获取一维数组中的元素值,代码如下:
泛型类的声明形式如下:
例如,定义一个泛型类 Test<T>,在该类中定义一个泛型类型的变量,代码如下。
说明以下几点:
在没有出现泛型之前,C# 提供了对 Object 的引用“任意化”操作。但这种任意化操作在执行某些强制类型转换时,有的错误也许不会被编译器捕捉,而在运行后出现异常。由此可见,强制类型转换存在安全隐患,所以 C# 提供了泛型机制。
本节就带着大家详细了解 C# 的泛型机制。
为什么要使用泛型
我们在开发程序时,经常会遇到功能非常相似的模块,只是它们处理的数据不一样。通常的处理方法是编写多个方法来处理不同的数据类型,那么有没有一种办法,可以用同一个方法来处理传入的不同类型参数呢?泛型就可以解决这类问题。例如,下面代码定义了 3 个方法,分别用来获取 int、double 和 bool 类型的原始类型。
public void GetInt(int i) { Console.WriteLine(i.GetType()); } public void GetDouble(double i) { Console.WriteLine(i.GetType()); } public void GetBool(bool i) { Console.WriteLine(i.GetType()); }调用上面方法的代码如下:
Program p = new Program(); p.GetInt(1); p.GetDouble(1.0); p.GetBool(true); 运行结果如下: System.Int32 System.Double System.Boolean观察上面的代码可以发现,除了传入的参数类型不同外,它们实现的功能是一样的。这时有人可能会想到 object 类型,可以将上面的代码优化成如下形式。
public void GetType(object i) { Console.WriteLine(i.GetType()); }上面优化的代码可以实现与第一段代码相同的功能,但是使用 object 会对程序的性能造成影响。遇到这种情况应该怎么办呢?泛型可以解决这个问题。
C#泛型类型参数
在定义泛型时,只需要指定泛型的类型参数,通常用 T 表示。它可以看作一个占位符,而不是一种类型,仅代表了某种可能的类型。在定义泛型时,T 出现的位置可以在使用时用任何类型来代替。类型参数 T 的命名准则如下。
1) 使用描述性名称命名泛型类型参数,除非单个字母名称完全可以让人了解它表示的含义。例如,使用代表一定意义的单词作为类型参数T的名称,代码如下。
public interface IStudent<TStudent> public delegate void ShowInfo<TKey, TValue>
2) 将T作为描述性类型参数名的前缀。例如,使用T作为类型参数名的前缀,代码如下:
public interface IStudent<T> { T Sex { get; } }例如,可以将前面章节中获取各种数据原始类型的代码优化成如下形式:
public void GetType<T>(T t) { Console.WriteLine(t.GetType()); }调用的代码可以修改成如下形式:
Program p = new Program(); p.GetType<int>(1); p.GetType<double>(1.0); p.GetType<bool>(true);为什么使用泛型可以解决上面的问题呢?这是因为泛型是延迟声明的,即在定义时并不需要明确指定具体的参数类型,而是把参数类型的声明延迟到了调用时才指定。这里需要注意的是,在使用泛型时,必须指定具体类型。
C#泛型方法
其实上面在优化获取各种数据原始类型的代码时,已经用到了泛型方法。泛型方法就是指在声明中包含类型参数 T 的方法,其语法格式如下:修饰符 void 方法名<类型参数T>(参数列表) { 方法代码 }
例如,定义一个泛型方法,获取一维数组中的元素值,代码如下:
public void GetValue<T>(T[] ts) { for (int i = 0; i < ts.Length; i++) Console.WriteLine(ts[i]); }
C#泛型类
除了方法可以是泛型的以外,类也可以是泛型的。泛型类的声明形式如下:
修饰符 class 类名<T> { 类代码 }声明泛型类与声明一般类的唯一区别是增加了类型参数
<T>
。例如,定义一个泛型类 Test<T>,在该类中定义一个泛型类型的变量,代码如下。
public class Test<T>//创建一个泛型类 { public T _T;//公共变量 }定义泛型类之后,如果要使用该类,则需要在创建对象时指定具体的类型,例如下面的代码:
// T是int类型 Test<int> testInt = new Test<int>(); testInt._T = 123; // T是string类型 Test<string> testString = new Test<string>(); testString._T = "123";
说明以下几点:
- 如果在泛型类中声明泛型方法,则在泛型方法中可以同时引用该方法的类型参数T和在泛型类中声明的类型参数 T。
- 在定义泛型类时,如果子类也是泛型的,那么继承时可以不指定具体类型。类实现泛型接口也是这种情况。