1. 什么是泛型(Generics)

C#泛型通过参数化类型,实现同一份代码操作多个数据类型,实现了代码的复用。

C#编译器把代码编译为 IL代码时,采用特殊的占位符来表示类型,且有操作泛型的IL指令;当CLR真正运行代码时,JIT编译为真正的类型,即类型的晚绑定。

如果不使用泛型,对于不同的参数类型(int,double,single)可能都要重载(overloading)一遍,但使用泛型则减少了代码量,同时获得了强类型的支持。

泛型支持对参数类型进行约束,包括有一个主约束和多个次约束。有以下五种类型的约束:

  1. T:strcut,值类型
  2. T:class,引用类型
  3. T:new(),必须有public无参构造函数,同其他约束放在一起时,必须放在最后
  4. T:基类名,必须是基类或其子类
  5. T:接口名称,必须是接口或实现指定的接口

Generic classes and methods combine reusability, type safety and efficiency in a way that their non-generic counterparts cannot. Generics are most frequently used with collections and the methods operate on them.

Version 2.0 of the .NET Framework class library provides a new namespace, System.Collections.Generic, which contains several new generic-based collection classes.

In most cases, you should use the List<T> class provided by the .NET Framework class library instead of creating your own.

// type parameter T in angle brackets
public class GenericList<T> 
{
    // The nested class is also generic on T.
    private class Node
    {
        // T used in non-generic constructor.
        public Node(T t)
        {
            Next = null;
            Data = t;
        }
        public Node Next{get;set;}
        public T Data {get; set;} 
    }

    private Node head;
    public GenericList() 
    {
        head = null;
    }

    //向前添加
    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;
        }
    }
}

class TestGenericList
{
    public static void Main()
    {
        // int is the type argument
        GenericList<int> list = new GenericList<int>();

        for (int x = 0; x < 10; x++)
        {
            list.AddHead(x);
        }

        foreach (int i in list)
        {
            System.Console.Write(i + " ");
        }
        System.Console.WriteLine("\nDone");
    }
}

//out : 9 8 7 6 5 4 3 2 1 0
//out : Done

2. 泛型之前,ArrayList有什么缺点?

ArrayList dynamically resizes, it grows in capacity as elements are added(if space is needed).

当容量不足时,ArrayList会自动增加容量。

ArrayList.AddRange() 方法使用了 Array.Copy() 方法,性能要比for循环好一些。

ArrayList.Add( object value) ,可以添加各种类型。

所以用下标访问一个元素时,得到的是object,使用前要进行类型转换。

class Program
{
    static void Main()
    {
        //
        // Create an ArrayList with three strings.
        //
        ArrayList list = new ArrayList();
        list.Add("man");
        list.Add("woman");
        list.Add("plant");
        //
        // Loop over ArrayList.
        //
        for (int i = 0; i < list.Count; i++)
        {
            string value = list[i] as string;//类型转换
            Console.WriteLine(value);
        }
    }
}

List versus ArrayList (List vs ArrayList)(泛型 vs 非泛型)

List 比 ArrayList不仅仅避免了 boxing and unboxing , 同时在代码编写时就可以检测类型匹配,减少代码错误。

List.BinarySearch() 只有在List已经排序过才能正常工作。

ArrayList is a collection that is best avoided. But it is often used in older legacy programs—so it must be supported. Newer .NET Framework versions offer better collections.


Array vs ArrayList

Array 是一个存储相同元素类型固定大小的顺序集合。

  1. ArrayList因为内部使用的是 object,所以可以存放各种类型,但会频繁装箱拆箱。
  2. ArrayList是容量大小动态变化,可以自动增长。

ArrayList

所以,性能排序: Array > List > ArrayList;避免使用ArrayList


3. 重载 vs 泛型

重载: 同一个方法名,不同的参数类型、个数、或顺序

泛型:一个方法通过类型参数化,可以操作多种数据类型