我们在日常的开发任务中,经常遇到对不同的数据结构执行相同的操作,例如有一个方法传入的参数可能是字符串也可能是数字,这样的情况下,一般我们是直接传入一个object类型的参数,以便于可以实现这样的功能。例如以下代码。

private static void Show(object a)

    {

        Console.WriteLine(a.ToString());

}

这样的代码可是实现我们需要的功能,但是确定也很明显:1、只是传入一个object类型的参数,对于调用方来说,根本不知道应该传入一个什么类型的参数,很有可能以为参入参数的问题造成代码运行失败。2.object是一个引用类型,如果我们要处理的是一个值类型,那么就会产生装箱和拆箱的操作,频繁的装箱拆箱会对程序的性能造成极大的影响。在这样的需求下,C#2.0引入了泛型的概念,用于提供通用的功能以及编译时的类型安全。

一、泛型的定义

泛型的定义非常简单,<T>即可<>尖括号不能省略,T代表需要操作的具体类型,T不是固定的你可以使用任何有意义的符号代替。例如以下定义

private static void Show<TValue>(TValue a)

    {

        Console.WriteLine(a.ToString());//TValue代表需要操作的类型,需要注意的是TValue是类型而不是实例

}

泛型的定义可以放在方法上面,也可以放在整个类上面,放在方法上面那么只有当前方法是泛型方法,而直接放在类上面,则是把整个类全部定义为了泛型类,类内部的任何方法再使用此泛型的时候都可以不用再定义,如果需要定义多个泛型参数,则使用逗号隔开所有的参数,例如

private static void Show<TKey,TValue>(TValue a)

    {

        Console.WriteLine(a.ToString());

}

二、泛型方法的使用

定义了泛型方法就要去使用它,假设定义了如下的泛型方法

private static TValue Show<TValue>(TValue a)

    {

        Console.WriteLine(a.ToString());

        return a;

}

那么应该怎么调用他呢?

Show<string>("此坑已满");

Show<int>(123);

在<>中使用需要操作的类型代替TValue这个符号

 

 

上面就是调用泛型方法的结果。

三、泛型约束

有时候我们需要我们的泛型参数满足一定的条件,例如我们需要T继承自IComparable接口,或者我们要求T不能是值类型,只能是引用类型这样的需求,该怎样满足呢?很简单,使用where即可,例如以下定义

//以下定义要求TValue必须是一个引用类型

private static TValue Show<TValue>(TValue a) where TValue:class

    {

        Console.WriteLine(a.ToString());

        return a;

}

有了这样的定义,如果我们在调用泛型方法的时候把TValue定义为了一个值类型,那么VS的智能提示就会在编译时报错,这样就提供了编译时的类型安全。例如

 

如果是要求TValue要满足多个要求的话,则使用逗号分开即可

private static TValue Show<TValue>(TValue a) where TValue:class,IComparable,new ()

    {

        Console.WriteLine(a.ToString());

        return a;

}

下面是常用的一些约束规则

  1. 要求必须是引用类型,where T:class
  2. 要求必须是值类型,where T:struct
  3. 约束中可以有多个接口,但只能有一个基类,因为类型继承要求单基类继承
  4. new ()要求T必须有一个无参构造函数,同时new()必须放在约束的最后,同时C#不支持约束带参数的构造函数

其他更加详细的规则请参考MSDN

四、C#中常见的泛型

泛型可以用在方法,类型,接口,委托等等对象上面,在C#中有很多已经定义好的泛型供我们直接使用,例如List<T>,Dictionary<TKey,TValue>,Func<T1,T2>,Action<T>等等。他们的使用方法,请参考MSDN或者自行百度,谢谢!