第三章 C# 泛型

当两个模块功能相似,仅仅只是类型不同的时候,你会怎么办呢。请看以下代码:

public class IntClass
        {
            List<int> Intlist = new List<int>();
            public void AddList(int i)
            {
                Intlist.Add(i);
            }
        }
        public void Main()
        {
            IntClass c1 = new IntClass();
            c1.AddList(1);
            c1.AddList(1);
        }
View Code

但是当我们想c1.AddList("hello word");要插入一个字符串类型的时候,你会怎么做呢?

二逼程序员会这样做:

public class StringClass
        {
            List<string> Intlist = new List<string>();
            public void AddList(string i)
            {
                Intlist.Add(i);
            }
        }
View Code

普通程序员会这样做:

public class ObjClass
        {
            List<object> Intlist = new List<object>();
            public void AddList(object i)
            {
                Intlist.Add(i);
            }
        }
View Code

仔细想想,不断装箱拆箱是否效率低下呢,当我们要插入bool,char,datetime.....等等类型的时候,我们需要copy这么多类吗?这时我们就用到了泛型。

 

1.泛型的声明:

public class Class1<T>
    {
        private List<T> List = new List<T>();
        public List<T> GetList()
        {
            return List;
        }
        public void AddList(T t)
        {
            List.Add(t);
        }
    }
View Code

2.泛型的默认值:

T t=defalut(T); 如果T是值类型,则t=0;如果T是引用类型,则t=null.

3.泛型约束:

 接口约束:where T:Interface   必须显示的实现接口

 基类约束:where T:BaseClass 参数必须为BaseClass或者派生类

 类约束:where T:class T必须是引用类型

 值类型约束: where T:struct T必须是值类型

 构造函数约束: where T:new()  必须有默认的构造函数

 泛型类型约束: Where T:T1

4静态成员:

不同类型的泛型可以认为是不同的类。  所有静态成员只能在同类中共享。

public class mm<T>
{
public static string Name{get;set;}
}

mm<int> a,mm<int> b,mm<sting>c       a,b可以共享Name,c不能

 

5.泛型类中的方法重载
方法的重载在.Net Framework中被大量应用,他要求重载具有不同的签名。在泛型类中,由于通用类型T在类编写时并不确定,所以在重载时有些注意事项,这些事项我们通过以下的例子说明:

public class Node<T, V>

    {

        public T add(T a, V b)          //第一个add

        {

            return a;

        }

        public T add(V a, T b)          //第二个add

        {

            return b;

        }

        public int add(int a, int b)    //第三个add

        {

            return a + b;

        }

}

上面的类很明显,如果T和V都传入int的话,三个add方法将具有同样的签名,但这个类仍然能通过编译,是否会引起调用混淆将在这个类实例化和调用add方法时判断。请看下面调用代码:

Node<int, int> node = new Node<int, int>();

    object x = node.add(2, 11);

这个Node的实例化引起了三个add具有同样的签名,但却能调用成功,因为他优先匹配了第三个add。但如果删除了第三个add,上面的调用代码则无法编译通过,提示方法产生的混淆,因为运行时无法在第一个add和第二个add之间选择。

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

        object x = node.add(2, "11");

   这两行调用代码可正确编译,因为传入的string和int,使三个add具有不同的签名,当然能找到唯一匹配的add方法。

由以上示例可知,C#的泛型是在实例的方法被调用时检查重载是否产生混淆,而不是在泛型类本身编译时检查。同时还得出一个重要原则:

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

 

泛型类的方法重写
方法重写(override)的主要问题是方法签名的识别规则,在这一点上他与方法重载一样,请参考泛型类的方法重载。

 

泛型的使用范围
本文主要是在类中讲述泛型,实际上,泛型还可以用在类方法、接口、结构(struct)、委托等上面使用,使用方法大致相同,就不再讲述。

 

 

posted @ 2015-08-06 23:48  《船长》  阅读(130)  评论(0编辑  收藏  举报