前言:

    此系列都为个人对C#的回顾,属于个人理解,新司机可参考、求老司机指点。如果有什么问题或不同见解,欢迎大家与我沟通!   


目录: 

   泛型是什么

泛型的好处及用途

如何声明使用泛型

泛型类

泛型方法

泛型接口

泛型委托

泛型约束

  • 泛型是什么

    通过“参数化类型(不指定类型)”来实现在同一份代码上操作多种数据类型。

     在声明时不指定类型,编译后查看IL代码可看到生成为占位符“`1”(1表示只有一个泛型参数,两个就是`2,以此类推)   ,调用时会生成不同类型的方法,也就是最终还是会生成多个方法!

    

  • 泛型的好处及用途

     我们来假设一个场景:需要在控制台输出各种类型(可能不太形象,个人感觉ORM框架中数据保存那块很形象)。

     在泛型没出现之前,我们基本都是采用以下这种方式来实现:

    

     这个时候该有人说了这样写以后扩展太麻烦,咱可以采用object,毕竟object是所有类型的基类,也就是以下这种:

    

     确实,类型不明确的地方可以使用object类型,一样可以达到目的。不过这种办法会引起:

     1.使用object导致的类型安全问题

     2.拆箱装箱导致性能下降

     泛型的出现就是为了解决以上几种情况的问题,上面那个例子可以改为:

    

     综其上述,泛型的好处有:

     1.泛型采用延迟声明思想,将“参数化类型”将类型抽象化,从而实现更为灵活的复用。

     2.泛型赋予了代码更强的类型安全,更高的效率,更清晰的约束。

     泛型的用途很广泛,在.net各处都有体现,比如常见的List<T>、IEnumerable<T>、ICollection<T>等等。个人觉得说起泛型就应该说说委托。。。

     例如:Linq中的方法都是采用的泛型加委托

     

  • 如何声明使用泛型

    泛型类:

     /// <summary>
/// 这就是一个泛型类,是不是很简单
/// </summary>
/// <typeparam name="T">类型参数</typeparam>
public class Generic<T>
{
/// <summary>
/// 泛型方法
/// </summary>
/// <param name="type">泛型参数,根据类指定</param>
/// <returns></returns>
public T OutPut(T type)
{
Console.WriteLine(type.GetType());
return default(T);
}
} public class Test
{
Generic<int> genericInt;
Generic<string> genericString;
public Test()
{
//泛型类调用1
genericInt = new Generic<int>();
genericInt.OutPut();
//泛型类调用2
genericString = new Generic<string>();
genericString.OutPut("我就是泛型方法,不过我的参数类型是根据类来决定的,我的兄弟会在下面粗现~~");
}
}

    泛型方法:

     public class Generic<T>
{
/// <summary>
/// 泛型方法
/// </summary>
/// <param name="type">泛型参数,根据类指定</param>
/// <returns></returns>
public T OutPut(T type)
{
Console.WriteLine(type.GetType());
return default(T);//default(T)返回类型默认值
} /// <summary>
/// 泛型方法,注意看,我与上面不同哦!调用也不同哦!
/// </summary>
/// <typeparam name="TResult"></typeparam>
/// <param name="tresult"></param>
/// <returns></returns>
public TResult GenericAction<TResult>(TResult tresult)
{
Console.WriteLine(tresult.GetType());
return default(TResult);
}
/// <summary>
/// 可以随便写,类上面也一样~~~~~
/// </summary>
public TResult GenericAction<TResult, LResult, SResult>(TResult tresult,LResult lresult,SResult sresult)
{
Console.WriteLine(tresult.GetType());
return default(TResult);
}
} public class Test
{
Generic<int> genericInt;
Generic<string> genericString;
Generic<DateTime> genericDateTime;
public Test()
{
//泛型类调用1
genericInt = new Generic<int>();
genericInt.OutPut();
//泛型类调用2
genericString = new Generic<string>();
genericString.OutPut("我就是泛型方法,不过我的参数类型是根据类来决定的,我的兄弟会在下面粗现~~");
//泛型方法调用3
genericDateTime = new Generic<DateTime>();
genericDateTime.GenericAction<string>("我的最终输出结果是根据方法的类型参数决定的,跟类无关!");
}
}
}

    泛型接口:

     //泛型接口
public interface IGeneric<T>
{
}
//普通类继承泛型接口,需要指定基类泛型类型
public class Generic : IGeneric<string>
{
}
//泛型类继承泛型接口
public class Test<T> : IGeneric<int>
{
}
//泛型类继承泛型接口,并运用子类的泛型类型
public class Test1<T> : IGeneric<T>
{
}
//随便怎么玩都可以~~~~~~~其他的大家都可以试试

    泛型委托:个人觉得泛型委托是个重点,在.net中处处体现了这点,比如我上面所说到的Linq方法。如果有对委托不熟悉的,我会在后面写一篇关于对委托的介绍。

       1.首先我们先自定义一个泛型委托

     class Program
{
//这里定义了一个无参有返回值的泛型的委托
public delegate T CustomDelegate<T>();
//这里定义了一个有参有返回值的泛型的委托
public delegate T CustomDelegate1<T>(T type); static void Main(string[] args)
{
//声明这个无参有返回值泛型委托
CustomDelegate<int> customDelegate = new CustomDelegate<int>(() => { return ; });//() => { return 1; }匿名方法
//调用这个泛型委托
customDelegate.Invoke(); //声明这个有参有返回值泛型委托
CustomDelegate1<string> customDelegate1 = new CustomDelegate1<string>((i) => { return i; });
customDelegate1.Invoke("有参有返回值"); //其他的无参无返回值,有参无返回值大家都可以试下,也可以尝试定义成多个参数的委托试试!!!
}
}

    2.微软在.net为我们封装好的三个泛型委托,为了简化咱们的工作量,不用自定义委托

 class Program
{
static void Main(string[] args)
{
//1.Func
Func<string> func = new Func<string>(() => { return default(string); }); //2.Action
Action<string> action = new Action<string>((i) => { }); //3.Predicate
Predicate<bool> pre = new Predicate<bool>((i) => { return true; }); //这三个泛型委托用处不同.
//比如Func就在Linq方法中经常用到,在F12进去之后可以看到类型参数上带有out修饰符
//Action,在F12进去之后可以看到类型参数上带有in修饰符
//in 与 out 则就是我们后面要说的逆变与协变了
//Predicate,则就是一个条件判断委托了
//具体的应用场景大家可以想象下
}
}

    泛型约束:

      在定义泛型类时,可以对客户端代码能够在实例化类时用于类型参数的类型种类施加限制。如果客户端代码尝试使用某个约束所不允许的类型来实例化类,则会产生编译时错误。这些限制称为约束。约束是使用 where 上下文关键字指定的。下表列出了六种类型的约束:

约束 说明

T:结构

类型参数必须是值类型。可以指定除 Nullable 以外的任何值类型。有关更多信息,请参见使用可空类型(C# 编程指南)。

T:类

类型参数必须是引用类型,包括任何类、接口、委托或数组类型。

T:new()

类型参数必须具有无参数的公共构造函数。当与其他约束一起使用时,new() 约束必须最后指定。

T:<基类名>

类型参数必须是指定的基类或派生自指定的基类。

T:<接口名称>

类型参数必须是指定的接口或实现指定的接口。可以指定多个接口约束。约束接口也可以是泛型的。

T:U

为 T 提供的类型参数必须是为 U 提供的参数或派生自为 U 提供的参数。这称为裸类型约束。

    1.T:结构

    2.T:类

    3.T:new()

 

    4.T:<基类名>

    5.T:<接口名称>

    6.T:U


扩展:

  让我们通过泛型与泛型委托来扩展一个IEnumerable方法(需要了解C#扩展方法)

     public static class Extends  //静态类
{
/// <summary>
/// 只要有一个满足于predicate条件就返回true
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <param name="tsource"></param>
/// <param name="predicate"></param>
/// <returns></returns>
public static bool MaxBool<TSource>(this IEnumerable<TSource> tsource, Func<TSource, bool> predicate)
{
foreach (var item in tsource)
{
if (predicate(item))
{
return true;
}
}
return false;
}
} static void Main(string[] args)
{
//为什么List能使用MaxBool()我就不用说了吧。。。。。
List<int> listA = new List<int>() { , , };
bool trueOrFalse = listA.MaxBool(item => item > );
}

   这里只是一个简单的例子,大家可以试试对其他的进行扩展!

 

C#:泛型(Generic)的更多相关文章

  1. Java - 泛型 ( Generic )

    Java - 泛型 ( Generic )     > 泛型的特点         > 解决元素存储的安全性问题         > 解决获取数据元素时,需要类型强转的问题     ...

  2. Java之集合初探(二)Iterator(迭代器),collections,打包/解包(装箱拆箱),泛型(Generic),comparable接口

    Iterator(迭代器) 所有实现了Collection接口的容器都有一个iterator方法, 用来返回一个实现了Iterator接口的对象 Iterator对象称作迭代器, 用来方便的实现对容器 ...

  3. 谈一谈从 Delphi 2009 之后就支援的重要功能 – 泛型 (Generic)

    前言 在C++的语言基础当中,除了物件导向.事件驱动的概念之外,模版设计(Template)也是非常重要的一环.然而,C++的开发人员能够善用模版设计的并不多.模版设计这个好物,一般还有一个名称,就是 ...

  4. JAVA中的泛型(Generic)

    Java泛型(Generic)简介 泛型是jdk1.5版本以后推出来的,表示类型参数化,让java能更具有动态性一些,让类型能变成参数传递. 要我自己感觉的话,泛型本身没啥用,跟反射在一起用,就体现出 ...

  5. Dephi泛型generic的应用

    Dephi泛型generic的应用   泛型在C++, C#中已有广泛应用,Delphi自2009版本也引入泛型,典型的应用如TList,TDictionary.如果你熟悉C#,其用法十分类似. 比如 ...

  6. Java基础之Comparable接口, Collections类,Iterator接口,泛型(Generic)

    一.Comparable接口, Collections类 List的常用算法: sort(List); 排序,如果需要对自定义的类进行排序, 那就必须要让其实现Comparable接口, 实现比较两个 ...

  7. Java自学-集合框架 泛型Generic

    ArrayList上使用泛型 步骤 1 : 泛型 Generic 不指定泛型的容器,可以存放任何类型的元素 指定了泛型的容器,只能存放指定类型的元素以及其子类 package property; pu ...

  8. C#泛型(Generic)

    一.什么是泛型 泛型(Generic)是C#语言2.0.通用语言运行时(CLR)2.0..NET Framework2.0推出来的新特性. 泛型为.NET框架引入类型参数(Type Parameter ...

  9. .NET知识梳理——1.泛型Generic

    1. 泛型Generic 1.1        引入泛型:延迟声明 泛型方法声明时,并未写死类型,在调用的时候再指定类型. 延迟声明:推迟一切可以推迟的. 1.2        如何声明和使用泛型 泛 ...

  10. C# 泛型Generic

    泛型(Generic),是将不确定的类型预先定义下来的一种C#高级语法,我们在使用一个类,接口或者方法前,不知道用户将来传什么类型,或者我们写的类,接口或方法相同的代码可以服务不同的类型,就可以定义为 ...

随机推荐

  1. iOS系列 基础篇 04 探究视图生命周期

    iOS系列 基础篇 04 探究视图生命周期 视图是应用的一个重要的组成部份,功能的实现与其息息相关,而视图控制器控制着视图,其重要性在整个应用中不言而喻. 以视图的四种状态为基础,我们来系统了解一下视 ...

  2. Windows Server 2012 虚拟化实战:网络(一)

    虚拟化对于计算的抽象,大家可能相对熟悉,也许都有在单机使用诸如Virtual PC或者Virtual Box的经验.使用的这些虚拟化软件的第一印象就是我们的CPU可以同时运行多套不同的操作系统,并且其 ...

  3. php类中的魔术方法

    1.构造函数 析构函数class pt{ function __construct($data) { echo "pt is start ..."; $this->pr($d ...

  4. Mellanox 8亿美元收购EZchip

    http://www.iccsz.com/site/cn/News/2015/10/08/20151008003916131771.htm Mellanox 8亿美元收购EZchip 目标电信运营商 ...

  5. Ubuntu管理开机启动服务项 -- 图形界面的Boot-up Manager

    有时学习时安装的服务太多,比如mysql.mongodb.redis.apache.nginx等等,它们都是默认开机启动的,如果不想让它们开机启动,用到时再自己手工启动怎么办呢? 使用sysv-rc- ...

  6. USACO . Your Ride Is Here

    Your Ride Is Here It is a well-known fact that behind every good comet is a UFO. These UFOs often co ...

  7. maven 详解

    Maven是基于项目对象模型(POM)的,可以通过一小段描述信息来管理项目构建,报告和文档的软件项目管理工具,是一种全新的项目构建方式,让我们的开发更加简单,高效.Maven主要做的是两件事: 开发规 ...

  8. scheduletask任务调度

    1.导入jar包 2.创建entity. package cn.happy.entity; public class Plan { //时间 private String date; //任务 pri ...

  9. polya/burnside 学习

    参考链接: http://www.cnblogs.com/hankers/archive/2012/08/03/2622231.html http://blog.csdn.net/raalghul/a ...

  10. Zabbix2.4.7源码安装手册

    一.安装Apache Server 注:使用root安装后,变更拥有者为your-user 1 安装环境 系统: CentOS release 6.6 软件: httpd-2.2.31 2 安装步骤 ...