前言:

    此系列都为个人对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. PostgreSQL隐藏字段tableoid

    问题来源: 今天群里有人问:tableoid字段在每行都有,而且一个表里面的值是重复的,这样不合理...... 因此做了一些分析: 1)创建了一个表 apple=# \d test_time Tabl ...

  2. IIS中启用ASP并连接Access数据库的解决办法

    1. IIS安装ASP模块 进入控制面板 ---- 打开或关闭Windows功能 选择如下所示两项,点击安装完成 2. 打开父路径许可 选择相应应用程序池 ----- 高级设置 ---- 将“启用父路 ...

  3. 树莓派3B初始化后一些必须的设置

    接上一篇,SSH已经登录成功(http://www.cnblogs.com/crosys/p/6220108.html) 1.树莓派系统的设置 1.1扩展系统空间 因为内存卡还有很多空间没有分配,第一 ...

  4. 如何给SVG填充和描边应用线性渐变

    给SVG元素应用填充和描边有三种方法(戳这里学习SVG填充和描边的相关内容).你可以使用纯色.图案或渐变.前面两种方法我们之前已经讲过了,现在我们来讨论第三种方法——渐变. SVG提供了两种渐变——线 ...

  5. Spring 下默认事务机制中@Transactional 无效的原因

    Spring中 @Transactional 注解的限制1. 同一个类中, 一个nan-transactional的方法去调用transactional的方法, 事务会失效 If you use (d ...

  6. PCD文件去除曲率的脚本

    在写一个重建算法的时候需要用到点坐标和法向的数据文件,于是向利用pcl中的法向计算模块来生成法向.输出后法向文件中包含曲率信息,但是这是不需要的.于是自己写了一个python小脚本实现格式转换. #- ...

  7. [LeetCode] Reverse Words in a String 翻转字符串中的单词

    Given an input string, reverse the string word by word. For example, Given s = "the sky is blue ...

  8. C语言学习 第十一次作业总结

    作业总结 两次的作业,都是和指针有关.从第一次的作业开始,我就多次让同学们思考这个问题:为什么要用指针,为什么在函数的形参中要使用指针.如果能够想明白这2个问题,那么同学们应该会指针的了解就差不多足够 ...

  9. hql中in关键字的用法

    hql: from " + FoodComment.class.getName() + " f where f.id in :groupIds" 封装的方法: publi ...

  10. 【BZOJ 3754】Tree之最小方差树

    http://www.lydsy.com/JudgeOnline/problem.php?id=3754 核心思想:暴力枚举所有可能的平均数,对每个平均数排序后Kruskal. 正确的答案一定是最小的 ...