泛型

简介: 通过使用泛型,我们可以极大地提高代码的重用度,同时还可以获得强类型的支持,避免了隐式的装箱、拆箱,在一定程度上提升了应用程序的性能。     泛型类实例化的理论     C#泛型类在编译时,先生成中间代码IL,通用类型T只是一个占位符。

    通过使用泛型,我们可以极大地提高代码的重用度,同时还可以获得强类型的支持,避免了隐式的装箱、拆箱,在一定程度上提升了应用程序的性能。

    泛型类实例化的理论

    C#泛型类在编译时,先生成中间代码IL,通用类型T只是一个占位符。在实例化类时,根据用户指定的数据类型代替T并由即时编译器(JIT)生成本地代码,这个本地代码中已经使用了实际的数据类型,等同于用实际类型写的类,所以不同的封闭类的本地代码是不一样的。按照这个原理,我们可以这样认为:

    泛型类的不同的封闭类是分别不同的数据类型。

 

    为什么要有泛型

    它可以避免重复代码。如果有几个类或者方法类似,实现功能相同,区别只是类型不一样,如int和string是,这是可以定义一个泛型。

    泛型类就类似于一个模板,可以在需要时为这个模板传入任何我们需要的类型。

 

  由一个例子引入:

  我们在算法中会学到排序,一个很经典的排序为冒泡排序法。将几个乱序的数字用冒泡发排序,我想大多数人会很快的写出来。

  我将例子弄详细一点。新建一张aspx的页面,放一个button和一个label服务器控件,双击button,自动生成响应方法。网页关键代码如下:

1 <asp:Button ID="Button1" runat="server" Text="对1,8,3,7,2排序" onclick="Button1_Click" />
2 <asp:Label ID="Label1" runat="server" Text=""></asp:Label>

  要实现排序,需要现有实现冒泡排序的类,我们新建一个ShortHelper类:

 1 public class ShortHelper {
 2         public void BubbleSort(int[] array)
 3         {
 4             int length = array.Length;
 5             for(int i=0;i<=length-2;i++)
 6                 for (int j = length-1; j >= 1; j--)
 7                 {
 8                     if (array[j] < array[j - 1])
 9                     {
10                         int temp = array[j];
11                         array[j] = array[j - 1];
12                         array[j - 1] = temp;
13                     }
14                 }
15         }
16 }

将相应函数补充完整:

 

protected void Button1_Click(object sender, EventArgs e)
{
            string endsort = "";
            ShortHelper shorter = new ShortHelper();
            int[] array = { 1, 8, 3, 7, 2 };
            shorter.BubbleSort(array);
            foreach (int i in array)
            {
                endsort += i.ToString() + ",";
            }
            int length = endsort.Length - 1;
            endsort = endsort.Substring(0, length);
            Label1.Text = endsort;
}

 

结果如下:

 

 

但是,我现在又想对英文字母或者byte进行排序,怎么办呢,当然直接修改类型是可以的。但是这样会造成代码的不简洁,重用性差。现在我们就引入泛型,泛型其实就是类似于C++中的模版,是一种解决方法的同法,将类型用一个类似于占位符的代替。修改后的类如下:

 1 public class ShortHelper<T> where T : IComparable {
 2         public void BubbleSort(T[] array)
 3         {
 4             int length = array.Length;
 5             for (int i = 0; i <= length - 2; i++)
 6                 for (int j = length - 1; j >= 1; j--)
 7                 {
 8                     if (array[j].CompareTo(array[j - 1]) < 0)//因为object是没有比较大小的方法的,不用IComparable会照成无法比较大小,CompareTo方法用于比较,前一个比后一个小,返回值<0,反之返回>0
 9                     {
10                         T temp = array[j];
11                         array[j] = array[j - 1];
12                         array[j - 1] = temp;
13                     }
14                 }
15         }
16 }

在网页中添加

1 <asp:Button ID="Button2" runat="server" Text="对f,a,s,t,v,b,e排序" onclick="Button2_Click" />
2 <asp:Label ID="Label2" runat="server" Text=""></asp:Label>

相应的相应函数为

 1         protected void Button1_Click(object sender, EventArgs e)
 2         {
 3             string endsort = "";
 4             ShortHelper<int> shorter = new ShortHelper<int>();   //注意此处
 5             int[] array = { 1,8,3,7,2};
 6             shorter.BubbleSort(array);
 7             foreach (int i in array)
 8             {
 9                 endsort += i.ToString() + ",";
10             }
11             int length = endsort.Length - 1;
12             endsort = endsort.Substring(0, length);
13             Label1.Text = endsort;
14         }
15 
16         protected void Button2_Click(object sender, EventArgs e)
17         {
18             string endsort = "";
19             ShortHelper<char> shorter = new ShortHelper<char>();   //注意此处
20             char[] array = { 'f', 'a', 's', 't', 'v', 'b', 'e' };
21             shorter.BubbleSort(array);
22             foreach (char i in array)
23             {
24                 endsort += i + ",";
25             }
26             int length = endsort.Length - 1;
27             endsort = endsort.Substring(0, length);
28             Label2.Text = endsort;
29         }

运行结果为:

当然,泛型的用法不仅仅就这,还有泛型接口,泛型方法等等。

 

    优点:

    1、性能:避免隐式的装箱和拆箱

    如AarryList(在添加数据时装箱,读取时拆箱)和List<T>区别

    2、类型安全:

    泛型的另一个特性是类型安全。与ArrayList类一样,如果使用对象,可以在这个集合中添加任意类型。下面的例子在ArrayList类型的集合中添加一个整数、一个字符串和一个MyClass类型的对象:

1 ArrayList list = new ArrayList();
2 list.Add(44);
3 list.Add("mystring");
4 list.Add(new MyClass());

  如果这个集合使用下面的foreach语句迭代,而该foreach语句使用整数元素来迭代,编译器就会编译这段代码。但并不是集合中的所有元素都可以转换为int,所以会出现一个运行异常:

1 foreach (int i in list)
2 {
3     Console.WriteLine(i);
4 }

  错误应尽早发现。在泛型类List<T>中,泛型类型T定义了允许使用的类型。有了List<int>的定义,就只能把整数类型添加到集合中。编译器不会编译这段代码,因为Add()方法的参数无效:

1 List<int> list = new List<int>();
2 list.Add(44);
3 list.Add("mystring");   // compile time error
4 list.Add(new MyClass());   // compile time error

    3、二进制代码的重用:

    泛型允许更好地重用二进制代码。泛型类可以定义一次,用许多不同的类型实例。

   类型参数约束

    程序员在编写泛型类时,总是会对通用数据类型T进行有意或无意地有假想,也就是说这个T一般来说是不能适应所有类型,但怎样限制调用者传入的数据类型呢?这就需要对传入的数据类型进行约束,约束的方式是指定T的祖先,即继承的接口或类。因为C#的单根继承性,所以约束可以有多个接口,但最多只能有一个类,并且类必须在接口之前。

    除了可以约束类型参数T 实现某个接口以外,还可以约束T 是一个结构、T 是一个类、T 拥有构造函数、T 继承自某个基类等。

    泛型方法

    在泛型方法中,泛型类型用方法声明来定义。

 

1 void Swap<T>(ref T x, ref T y)
2 {
3   T temp;
4   temp = x;
5   x = y;
6   y = temp;
7 }

 

把泛型类型赋予方法调用,就可以调用泛型方法:

1 int i = 4;
2 int j = 5;
3 Swap<int>(ref i, ref j);

但是,因为C#编译器会通过调用Swap方法来获取参数的类型,所以不需要把泛型类型赋予方法调用。泛型方法可以像非泛型方法那样调用:

1 int i = 4;
2 int j = 5;
3 Swap(ref i, ref j);

当一般方法与泛型方法具有相同的签名时,会覆盖泛型方法。

    泛型类的特性

    1、默认值:不能把null赋予泛型类型。原因是泛型类型也可以实例化为值类型,而null只能用于引用类型。为了解决这个问题,可以使用default关键字。通过default关键字,将null赋予引用类型,将0赋予值类型。

        T doc = default(T);

  2、约束:如果泛型类需要调用泛型类型上的方法,就必须添加约束。

 

约    束

说    明

where T : struct

使用结构约束,类型T必须是值类型

where T : class

类约束指定,类型T必须是引用类型

where T : IFoo

指定类型T必须执行接口IFoo

where T : Foo

指定类型T必须派生于基类Foo

where T : new()

这是一个构造函数约束,指定类型T必须有一个默认构造函数

where T : U

这个约束也可以指定,类型T1派生于泛型类型T2。该约束也称为裸类型约束

 

  3、继承:泛型类型可以执行泛型接口,也可以派生于一个类。泛型类可以派生于泛型基类:

1 public class Base<T>
2 {
3 }
4 public class Derived<T> : Base<T>{}

  4、静态成员:泛型类的静态成员需要特别关注。泛型类的静态成员只能在类的一个实例中共享。

总结:

  泛型。通过泛型类可以创建独立于类型的类,泛型方法是独立于类型的方法。增加代码的重用性。接口、结构和委托也可以用泛型的方式创建。泛型引入了一种新的编程方式。

 

参考资料:http://www.cnblogs.com/JimmyZhang/archive/2008/12/17/1356727.html,《C#高级编程第六版》

 



目录
相关文章
|
8月前
|
存储 安全 Java
泛型的使用
泛型的使用
40 0
|
1月前
什么是泛型,泛型的具体使用?
什么是泛型,泛型的具体使用?
|
1月前
|
存储 算法 容器
什么是泛型?
什么是泛型?
10 0
|
5月前
|
存储 安全 Java
这还是你认识的泛型吗???!
这还是你认识的泛型吗???!
34 0
|
6月前
|
存储 算法 编译器
泛型的讲解
泛型的讲解
40 0
|
9月前
|
存储 安全 Java
泛型的相关知识
泛型的相关知识
69 0
|
12月前
|
存储 Java 编译器
对泛型的认识
对泛型的认识
|
Java 编译器 API
泛型-详解
泛型-详解
103 0
泛型-详解
|
安全 JavaScript Java
泛型中的 T、E、K、V、?等等,究竟是啥?
泛型中的 T、E、K、V、?等等,究竟是啥?
泛型中的 T、E、K、V、?等等,究竟是啥?
|
安全 Java 编译器
你了解泛型吗?
面向对象编程中,多态算是一种泛化机制。你可以将方法的参数类型设置为基类,那么该方法就可以接受从这个基类中导出的任何类作为参数,这样的方法将会更具有通用性。此外,如果将方法参数声明为接口,将会更加灵活。