.NET泛型或许是借鉴于C++泛型模版,借助它可以实现对类型的抽象化、泛型处理,实现了类型和方法之间的解耦。一个最经典的运用是在三层架构中,针对不同的领域模型,在基接口、基类中实现针对各个领域模型的泛型处理。

本篇主要包括:
为什么需要泛型
    ※ 不用泛型
    ※ 使用泛型
    ※ 泛型的运行时本质
泛型语法
典型的泛型类

为什么需要泛型

不用泛型

来看一个比较类型的方法。

public class Calculator
{
public static bool AreEqual(int value1, int value2)
{
return value1 == value2;
}
}

在客户端调用。

class Program
{
static void Main(string[] args)
{
bool result = Calculator.AreEqual(1, 2);
if (result)
{
Console.WriteLine("相等");
}
else
{
Console.WriteLine("不等");
}
Console.ReadKey();
}
}

运行结果:不等

不用泛型的缺点一:不是类型安全

如果我们想使用现在的方法来比较字符串类型。

bool result = Calculator.AreEqual("A", "B");

这时,看到编译器报错。从这点来看,AreEqual()方法不是类型安全的方法,当输入string类型,编译器就会报错。

如果把AreEqual()方法的参数类型改成object,编译器就不再报错。

public class Calculator
{
public static bool AreEqual(object value1, object value2)
{
return value1 == value2;
}
}

以上,运行也正常。

不用泛型的缺点二:装箱与拆箱导致性能降低

现在,对于AreEqual(object value1, object value2),从方法本身来讲是没有问题的,但在客户端调用的时候,比如我们还是想比较值类型。

bool result = Calculator.AreEqual(1, 2);

在运行时,当整型值类型参数1和2传递、赋值给AreEqual(object value1, object value2)中的引用类型参数value1和value2的时候,发生了一次"装箱"操作。而当把引用类型转换成值类型的时候,又会发生一次"拆箱"操作,这导致性能的降低。

使用泛型

把AreEqual()改成泛型方法。

public class Calculator
{
public static bool AreEqual<T>(T value1, T value2)
{
return value1.Equals(value2);
}
}

于是,在客户端可以这样:

bool result = Calculator.AreEqual<string>("A", "A");
bool result = Calculator.AreEqual<int>(5, 3);

由此,使用泛型的好处有:
1、实现了方法和类型的解耦。
2、不会造成类型转换,规避了因装箱于拆箱引起的性能问题。
3、泛型保证了类型的绝对安全。

当然,还可以把T的位置放在类上:

public class Calculator<T>
{
public static bool AreEqual(T value1, T value2)
{
return value1.Equals(value2);
}
}

然后这样使用:

bool result = Calculator<string>.AreEqual("A", "A");
bool result = Calculator<int.AreEqual(1, 2);

泛型的运行时本质

CLR中有专门的IL指令支持泛型操作。
→初次编译时,生成IL代码和元数据,T只是类型占位符,在编译时不进行实例化
→JIT编译时,以实际类型替换元数据中的T占位符
→将元数据转换为本地代码

泛型语法

class MyArray<T> where T : Student, new()
{
private T[] _items;
public T myData; public MyArray()
{
myData = default(T);
} public void Add(T item)
{}
}

创建泛型实例要指定实际的数据类型:
MyArray<Int32> myArr = new MyArray<Int32>();

值类型的默认值为0,引用类型的默认值为null,使用泛型默认值:
myData = default(T);

泛型约束:
T : 基类名,表示必须是基类名的派生类
T :new(), 表示必须具有无参构造函数,new()约束必须放在最后面
T :struct, 表示必须是值类型
T :class, 表示必须是引用类型
T :接口名,表示必须实现该接口,或实现该接口的接口

泛型类本质上仍然是一个类,依然可以继承:

internal class GenericeComparer<T> : Comparer<T> where T : IComparable<T>
class MyArray<T> : ArrayList

典型的泛型类

在System.Collections.Generic命名空间和System.Collections.ObjectModel中,定义了不同的泛型类和泛型接口,这些泛型多为集合类。

List<T> 对应ArrayList集合类
SortedList<TKey, TValue> 对应SortedList集合类
Queue<T> 先进先出的集合类
Stack<T> 后进先出的集合类
Collection<T> 自定义泛型集合的基类
Dictionary<TKey, TValue> 对应于Hashtable集合类

参考资料:
《你必须知道的.NET(第2版)》,作者王涛。

".NET泛型"系列包括:

.NET泛型01,为什么需要泛型,泛型基本语法

.NET泛型02,泛型的使用

.NET泛型03,泛型类型的转换,协变和逆变

.NET泛型04,使用Lazy<T>实现延迟加载

.NET泛型01,为什么需要泛型,泛型基本语法的更多相关文章

  1. [C# 基础知识梳理系列]专题六:泛型基础篇——为什么引入泛型

    引言: 前面专题主要介绍了C#1中的2个核心特性——委托和事件,然而在C# 2.0中又引入一个很重要的特性,它就是泛型,大家在平常的操作中肯定会经常碰到并使用它,如果你对于它的一些相关特性还不是很了解 ...

  2. 对比两个同类型的泛型集合并返回差异泛型集合 ——两个List<类名>的比较

    1: /// <summary> 2: /// 对比两个同类型的泛型集合并返回差异泛型集合 3: /// </summary> 4: /// <typeparam nam ...

  3. java 泛型详解(普通泛型、 通配符、 泛型接口)

    java 泛型详解(普通泛型. 通配符. 泛型接口) JDK1.5 令我们期待很久,可是当他发布的时候却更换版本号为5.0.这说明Java已经有大幅度的变化.本文将讲解JDK5.0支持的新功能---- ...

  4. 3. Java面向对象之泛型-指定多个泛型

    3. Java面向对象之泛型-指定多个泛型 package generic; class MutiGeneric<K, T> { private K key; private T take ...

  5. java泛型基础、子类泛型不能转换成父类泛型

    参考http://how2j.cn/k/generic/generic-generic/373.html 1.使用泛型的好处:泛型的用法是在容器后面添加<Type>Type可以是类,抽象类 ...

  6. java泛型(二)、泛型的内部原理:类型擦除以及类型擦除带来的问题

    微信公众号[程序员江湖] 作者黄小斜,斜杠青年,某985硕士,阿里 Java 研发工程师,于 2018 年秋招拿到 BAT 头条.网易.滴滴等 8 个大厂 offer,目前致力于分享这几年的学习经验. ...

  7. java泛型基础、子类泛型不能转换成父类泛型--未完待续

    参考http://how2j.cn/k/generic/generic-generic/373.html 1.使用泛型的好处:泛型的用法是在容器后面添加<Type>Type可以是类,抽象类 ...

  8. 泛型 System.Collections.Generic及泛型继承、运算符、结构、接口、方法、委托、事件、可空类型等

    一.定义泛型类 void Main() { //实例化泛型类时,才指定具体的类型 MyGenericClass<); Console.WriteLine(MyGeneri.InnerT1Obje ...

  9. java数据类型:集合存储元素类型限制<泛型> ;自定义类指定泛型<T> 以及限制用法;派生子类泛型<T> super(泛型内参数); 泛型通配符?以及?限制用法

    问题背景 Java 集合有个缺点,把一个对象"丢进"集合里之后,集合就会"忘记"这个对象的数据类型,当再次取出该对象时 该对象的编译类型就变Object类型(其 ...

随机推荐

  1. Knockout.Js官网学习Demo(使用VS2012或者VS2013均可打开)

    https://pan.baidu.com/s/1gf9JZ8n#list/path=%2F

  2. Java字符串常见实例与函数

    字符串比较 字符串函数 compareTo (string) ,compareToIgnoreCase(String) 及 compareTo(object string) 来比较两个字符串,并返回字 ...

  3. SSIS 学习之旅 第一个SSIS 示例(二)

    这一章还是继上一章例子 进行一些小的知识扩展.主要是为了让大家更快的上手SSIS. 概要设计:    1.按用户组生成CSV文件到Pending目录下,    2.移动Pending目录下的CSV文件 ...

  4. 不用的代码,存一份--用tornado实现的websocket

    因为现在使用Channels来实现啦, 这样就在Django的体系里自已弄完了. 方便后期代码维护和服务器部署. 这份土陋的东东,就放起来吧. 毕竟,通过读取文件来返回实时websocket,不适应于 ...

  5. 利用Metrics+influxdb+grafana构建监控平台

    https://blog.csdn.net/fishmai/article/details/51817429

  6. 一些你可能需要的okhttp实现

    https://blog.csdn.net/qq_17766199/article/details/53186874 今天分享一些我在项目中使用到的okhttp实现,由简至难.(以下内容均在okhtt ...

  7. Java学习(Map接口)

    一.概述: 我们通过查看Map接口描述,发现Map接口下的集合与Collection接口下的集合,它们存储数据的形式不同,如下图. 1. Collection中的集合,元素是孤立存在的(理解为单身), ...

  8. s12-day01-work02 python多级菜单展示

    README # README.md # day001-work-2 @南非波波 功能实现:多级菜单展示 流程图: ![](http://i.imgur.com/VTPPhZU.jpg) 程序实现: ...

  9. ASP.NET WebAPI 04 Model绑定

    在前面的几篇文章中我们都是采用在URI中元数据类型进行传参,实际上ASP.NET Web API也提供了对URI进行复杂参数的绑定方式--Model绑定.这里的Model可以简单的理解为目标Ancti ...

  10. ASP.NET WebAPI 01-Demo

    WebAPI作为构建RESTful的平台出来有段时间了,加上最近也在用,所以想把自己的心得记录下来.我就以一个简单的增删查改作为开篇. 准备 实体类(Figure)的定义. public class ...