【转帖】为什么使用泛型

原帖:http://blog.csdn.net/jecray/archive/2007/04/13/1563978.aspx

 有好久一段时间,我经常使用.net 1.1开发程序,发现.net 1.1缺少类似c++中的模板功能。这种支持类型参数的功能可以使我们设计一个有泛型的类,在运行时检测实际的类型。

这样意味着用一个泛型参数T,你可 以写一个MyList<T>类,在使用MyList<int>, MyList<string> MyList<MyClass>时不需要担心在运行时进行转换或装箱操作。

.NET 2.0引入了一个新的名字空间 System.Collections.Generic,他包括了支持泛型的类,例如:List, Queue, Stack, LinkedList。利用他们可以使你的程序更加有效率。

泛型的优点

.NET 2.0之前,泛型是通过 将特定类型和基类System.Object相互转换实现的。这种方法具有很大的局限性,比如ArrayListArrayList是一个非常好用 的集合类,可以随意存储任何值类型和引用。

ArrayList list1 = new ArrayList(); 
    list1.Add(
3); 
    list1.Add(
105); 
    
//...
    ArrayList list2 = new ArrayList();
    list2.Add(
"First item."); 
    list2.Add(
"Second item");
    
//...

但是这种便利是以性能为代价的,任何被加到ArrayList的引用或值都被显示地转换成System.Object。如果那些项是 值类型,他们在加入时必须装箱,在取出时拆箱。类型转换,装箱,拆箱操作降低了性能,特别在需要对一个大的集合进行拆装箱时,性能的损耗是巨大的。

所以我们需要一个灵活的ArrayList同时提供更好的性能和支持多种类型。是否可以为ArrayList添加一个类型参 数呢?这正式泛型所提供的。泛型可以避免把所有项转换成Object,也可以使编辑器做类 型检查。

Sytem.Collections.Generic中的List<T>进行相 同的操作:

List<int> list1 = new List<int>();
    list1.Add(
3); //不需要装箱和类型转换
    list1.Add("First item"); // 编译时错误

List<T>ArrayList使用的不同只是 在声明和实例化时多了一个类型参数。而换来的好处是创建的List不但比ArrayList安全,而且速度要快,特别是在List中 存储值类型的时候。

泛型类

泛型类将操作封装成不针对特有的数据类型。泛型类最普遍的用法是实现linked lists, hash tables, stacks, queues, trees等,他们是以 相同的方式添加删除项而不关心项的数据类型。

public class Node <T>
    
{
        T head;
        T next;
    }

这里T是一个类型参数,我们可以设置成 任何数据类型。

这个类可以这样实例化

Node<string> node = new Node<string>();

这样就告诉编译器headnext属性是string

泛型方法

将一个方法加上类型参数的声明就是泛型方法。

void Swap<T>ref T left, ref T right)
    
{
        T temp;
        temp 
= left;
        left 
= right;
        right 
= temp;
    }

我们可以这样调用他

int a = 1;
int b = 2;
Swap 
<int> (a, b);

你可以忽略类型参数因为编译器会自动加上,下面方法调用依旧是正确的:

Swap (a, b);

设计自己的泛型类
下面的例子实现了一个泛型linked list

using System;
using System.Collections.Generic;
public class MyList<T> //type parameter T in angle brackets
{
    
private Node head;
    
    
// The nested class is also generic on T.
    private class Node 
    
{
        
private Node next;
        
//T as private member data type:
        private T data; 
        
//T used in non-generic constructor:
        
        
public Node(T t) 
        
{
            next 
= null;
            data 
= t;
        }

        
public Node Next
        
{
            
get return next; }
            
set { next = value; }
        }

 
        
//T as return type of property:
        public T Data 
        
{
            
get return data; }
            
set { data = value; }
        }

    }

 
    
public MyList()
    
{
        head 
= null;
    }

 
    
//T as method parameter type:
    public void AddHead(T t) 
    
{
        Node n 
= new Node(t);
        n.Next 
= head;
        head 
= n;
    }

 
    
public IEnumerator<T> GetEnumerator()
    
{
        Node current 
= head;
        
while (current != null)
        
{
            
yield return current.Data;
            current 
= current.Next;
        }

    }


}

注意上面类的声明

public class MyList<T>

T是类 型参数,在上面的代码中,Node的数据类型是T而不是intstring或其他。这样使程序员 方便地用这个类处理任何数据类型。

以下代码告诉我们如何用泛型类MyList<T>创建一个int list,只需简单的改 变类型参数,下面的代码就可以创建string list或其他自定义类型的list

class Program
    
{
        
static void Main(string[] args)
        
{
            
//int is the type argument.
            MyList<int> list = new MyList<int>(); 

            
for (int x = 0; x < 10; x++)
                list.AddHead(x);
 
            
foreach (int i in list)
                Console.WriteLine(i);
            
            Console.WriteLine(
"Done");
        }

    }

泛型可以使类具有重用性,类型安全和效率,泛型在集合中广泛的使用。

http://blog.csdn.net/chimomo/archive/2009/09/30/4620379.aspx

在 C#中,使用泛型会获得以下优势:

  1. 减少装箱和拆箱操作,提高性能
  2. 可以进行编译时类型检查

举 例说明:

使 用非泛型的集合类,利用 .NET Framework 基类库中的 ArrayList 集合类。ArrayList 是一个使用起来非常方便的集合类,无需进行修改即可用来存储任何引用或值类型。

  1. // The .NET Framework 1.1 way to create a list:  
  2. System.Collections.ArrayList list1 = new System.Collections.ArrayList();  
  3. list1.Add(8);  
  4. list1.Add("It is raining heavily outside.");  

但 这种方便是需要付出代价的。添加到 ArrayList 中的任何引用或值类型都将隐式地向上强制转换为 Object。 如果项是值类型,则必须在将其添加到列表中时进行装箱操作,在检索时进行取消装箱操作。强制转换以及装箱和取消装箱操作都会降低性能;尤其是在必须对大型 集合进行循环访问的情况下,装箱和取消装箱的影响将非常明显。

另 一个限制是缺少编译时类型检查;因为 ArrayList 将把所有项都强制转换为 Object, 所以在编译时无法防止客户端代码执行以下操作:

  1. System.Collections.ArrayList list = new System.Collections.ArrayList();  
  2. // Add an integer to the list.  
  3. list.Add(8);  
  4. // Add a string to the list. This will compile, but may cause an error later.  
  5. list.Add("It is raining heavily outside.");  
  6.   
  7. int t = 0;  
  8. // This causes an InvalidCastException to be returned.  
  9. foreach (int x in list)  
  10. {  
  11.     t += x;  
  12. }  

尽 管将字符串和 int 组合在一个 ArrayList 中的做法在创建异类集合时是完全合法的,有时是有意图的,但这种做法更可能产生编程错误,并且直到运行时才能检测到此错误。

在 C# 语言的 1.0 和 1.1 版本中,只能通过编写自己的特定于类型的集合来避免 .NET Framework 基类库集合类中的通用代码的危险。当然,由于此类不可对多个数据类型重用,因此将丧失通用化的优点,并且您必须对要存储的每个类型重新编写该类。

ArrayList 和其他相似类真正需要的是:客户端代码基于每个实例指定这些类要使用的具体数据类型的方式。这样将不再需要向上强制转换为 T:System.Object, 同时,也使得编译器可以进行类型检查。换句话说,ArrayList 需要一个 type parameter。这正是泛型所能提供的。在 N:System.Collections.Generic 命名空间的泛型 List<T> 集合中,向该集合添加项的操作类似于以下形式:

  1. // The .NET Framework 2.0 way to create a list  
  2. List<int> list1 = new List<int>();  
  3.   
  4. // No boxing, no casting:  
  5. list1.Add(8);  
  6.   
  7. // Compile-time error:  
  8. // list1.Add("It is raining heavily outside.");  

对于客户端代码,与 ArrayList 相比,使用 List<T> 时添加的唯一语法是声明和实例化中的类型参数。虽然这稍微增加了些编码的复杂性,但好处是您可以创建一个比 ArrayList 更安全(由于指定了Type,所以可以进行编译时类型检查)并且速度更快(由于对于值类型无需进行装箱拆箱操作)的列表,特别适用于列表项是值类型的情 况。

 

原文地址:https://www.cnblogs.com/cubean/p/1744354.html