C# -- 泛型(1)
简介:
先看看泛型的概念--“通过参数化类型来实现在同一份代码上操作多种数据类型。利用“参数化类型”将类型抽象化,从而实现灵活的复用”。
很多初学者在刚开始接触泛型的时候会比较难理解 “泛型” 在这里先把 “泛型”当作一个形容词 这样比较方便理解 因为很多东西都可以是泛型的 比如--
“泛型的类” ,“泛型的方法”,“泛型的接口”,“泛型的委托” 等...很多时候我们使用泛型可以极大减少代码重复使程序更加清爽,也可以避免不必要的‘装箱’ ‘拆箱’过程。
<泛型的引入|为什么要有泛型?>
在程序设计的过程中我们常常会遇到这样的情况:为了实现某一个功能我们一开始把方法写好,但后来我们发现同样的功能需要我们再写一次但是这次方法的参数类型和上次不一样了,这个时候按照敏捷软件开发的思想,不要过早的进行抽象和应对变化,当变化第一次出现时,使用最快的方法解决它,但变化第二次出现的时,在进行更好的架构设计,这样的目的是为了避免过度设计,因为有可能第二次变化永远也不会出现。考虑到功能一样,所这里我们通常会直接复制原方法的代码,然后修改一下参数类型即可快速解决;这样做确实没错,但是有的时候不仅出现了第二次变化 还出现了第三次...或者是更多次变化,继续使用CV大法修改方法的签名将会导致大量重复代码的出现,于是我们就会想,要是存在一个可以传递任何数据类型的方法那多好,即把这个方法的实现当成模板 把方法的签名抽象出来,于是我们引入了泛型。
下面我们来看一下具体的例子:
1.1使用CV大法
---------------输入多个 int类型,进行冒泡排序让它们依次重小到大输出,代码如下:
public class SortHelper
{
public void BubbleSort(int[] arr)
{
int length = arr.Length;
for (int i = ; i < length-; i++)
{
for (int j = ; j < length--i; j++)
{
if (arr[j]>arr[j+])
{
int temp=arr[j];
arr[j] = arr[j + ];
arr[j + ] = temp;
}
}
}
}
}
测试:
static void Main(string[] args)
{
SortHelper sorter = new SortHelper();
int[] a = { ,,,,,,,,}; sorter.BubbleSort(a);
//输出省略
}
输出为:0,1,2,2,3,4,5,5,8
---------------输入多个 Byte类型,进行冒泡排序让它们依次重小到大输出,代码如下:
这个时候我只要复制一下原来的方法改一下签名就可以了
public class SortHelper
{
public void BubbleSort(byte[] arr)
{
int length = arr.Length;
for (int i = ; i < length-; i++)
{
for (int j = ; j < length--i; j++)
{
if (arr[j]>arr[j+])
{
byte temp = arr[j];
arr[j] = arr[j + ];
arr[j + ] = temp;
}
}
}
}
}
这样做虽然可以,但是往后若要 处理N次各种其他 数据类时就 就要大量重复复制 严重影响代码的简洁度,而且当功能要扩展时 ,每个方法都要修改,维护起来非常不方便。
1.2使用泛型(泛型类):
我们自然而然的会这样想了如果可以把方法中的 参数类型 用一个 ”占位符“ 表示 每次 传入 什么类型 他就变成什么类型,这样就可以将这个方法当成一个模板用了(有点像Web编程中在Html中使用占位符)。
这里我们用 “T” 来便是这个特殊的参数类型,于是代码就变成了这样:
public class SortHelper
{
public void BubbleSort(T[] arr)
{
int length = arr.Length;
for (int i = ; i < length-; i++)
{
for (int j = ; j < length--i; j++)
{
if (arr[j]>arr[j+])
{
T temp = arr[j];
arr[j] = arr[j + ];
arr[j + ] = temp;
}
}
}
}
}
这里 T 代表 ”类型的类型“ 和 int ,string ...等数据类型相似,T 就是类型本身。让人兴奋的是真的有像 “T” 这样的特别存在,在.NET中叫做类型参数. 下面我们看看规范的代码--
这里我们把BubbleSort定义成泛型类 定义泛型类的一种方法是在类后面加上“<T>”
//定义泛型类SortHelper 这里“where T:IComparable” 是给类型参数T一个限制 -- 参数类型必须实现IComparable接口,否则无法通过编译
public class SortHelper<T> where T:IComparable
{
public void BubbleSort(T[] arr)
{
int length = arr.Length;
for (int i = ; i < length-; i++)
{
for (int j = ; j < length--i; j++)
{
if (arr[j].CompareTo(arr[j+])>)
{
T temp = arr[j];
arr[j] = arr[j + ];
arr[j + ] = temp;
}
}
}
}
}
测试:
static void Main(string[] args)
{
SortHelper<byte> sorter = new SortHelper<byte>();
byte[] a = { ,,,,,,,,}; sorter.BubbleSort(a); SortHelper<int> sorter1 = new SortHelper<int>();
int[] b = { , , , , , , , , }; sorter1.BubbleSort(b);
//输出省略
}
输出为:
0,1,2,2,3,4,5,5,8
0,1,2,2,3,4,5,5,8
---------------输入多个 自定义类型的实例,进行冒泡排序让它们依次重小到大输出,代码如下:
下面我们来模拟一下宠物店卖的猫 按价格排序
猫类:
public class cat:IComparable
{
public string name;
public int price; public int CompareTo(object obj)
{
cat catT = (cat)obj;
return this.price.CompareTo(catT.price);
} public cat(string name, int price)
{
this.price = price;
this.name = name;
}
}
测试:
static void Main(string[] args)
{
SortHelper<cat> sorter2 = new SortHelper<cat>();
cat cat1=new cat("猫1",);
cat cat2=new cat("猫2",);
cat cat3=new cat("猫3",);
cat[] c = { cat1, cat2, cat3 }; sorter2.BubbleSort(c);
//输出
for (int i = ; i < c.Length; i++)
{
Console.WriteLine("Name:"+c[i].name+" Price:"+c[i].price);
}
}
结果如图:

*泛型与集合类型(ArrayList)
概要:通过泛型可以大大提高集合类型的的性能恶化安全性。
下面我们来看一个例子
2.1 非泛型的集合类
先是 往集合里 存放 3 个数据
ArrayList list = new ArrayList();
int listSize = ; for (int i = ; i < listSize; i++)
{
list.Add(i);
} for (int i = ; i < listSize; i++)
{
int value = (int)list[i];
Console.WriteLine(value);
}
测试:
输出
0
1
2
有经验的读者在这里可能会注意到了,这样子写虽然能运行通过,但是这里当 list每次调用Add方法时就做了一次 ” 装箱 “ 操作,接着每次取数据时对list的元素进行一次强制转换 (int)list[i] 同时也做了一次 “ 拆箱 ”操作,这两个操作对.NET来说是比较耗时的,当操作的次数越多效果就越明显;
2.2下面我们将 listSize 设置成 1000000 然后用 开始和结束DateTime.Now 来获取消耗的时间:
ArrayList list = new ArrayList();
int listSize = ;
long StarTime = DateTime.Now.Ticks;
for (int i = ; i < listSize; i++)
{
list.Add(i);
} for (int i = ; i < listSize; i++)
{
int value = (int)list[i];
}
long EndTime = DateTime.Now.Ticks; Console.WriteLine("使用ArrayList,耗时:{0} Ticks", EndTime - StarTime);
测试:
结果

2.3 使用泛型集合类型(泛型数组)
List<int> list = new List<int>();
int listSize = ;
long StarTime = DateTime.Now.Ticks;
for (int i = ; i < listSize; i++)
{
list.Add(i);
} for (int i = ; i < listSize; i++)
{
int value =list[i];
}
long EndTime = DateTime.Now.Ticks; Console.WriteLine("使用List<int>,耗时:{0} Ticks", EndTime - StarTime);
测试:

比较上述2次执行的结果我们会发现,使用 ArrayList 的耗时是使用 List<int> 的2倍多 ,随着次数的增大差距会越来越明显!
总结:
看到这里相信大家明白为什么要引入泛型了吧,通过使用泛型-
1.可以避免同种功能代码的大幅度重复出现使我们的代码更加简洁/可读性更高
2.方便扩展维护,灵活度高
3.避免隐式的装箱拆箱,提高程序运行速度
推荐一篇对初学者较有帮助的文章:传送门
出自Keiling_J'Blog:http://www.cnblogs.com/keiling/p/3672346.html
C# -- 泛型(1)的更多相关文章
- 一起学 Java(三) 集合框架、数据结构、泛型
一.Java 集合框架 集合框架是一个用来代表和操纵集合的统一架构.所有的集合框架都包含如下内容: 接口:是代表集合的抽象数据类型.接口允许集合独立操纵其代表的细节.在面向对象的语言,接口通常形成一个 ...
- .NET面试题系列[8] - 泛型
“可变性是以一种类型安全的方式,将一个对象作为另一个对象来使用.“ - Jon Skeet .NET面试题系列目录 .NET面试题系列[1] - .NET框架基础知识(1) .NET面试题系列[2] ...
- C#4.0泛型的协变,逆变深入剖析
C#4.0中有一个新特性:协变与逆变.可能很多人在开发过程中不常用到,但是深入的了解他们,肯定是有好处的. 协变和逆变体现在泛型的接口和委托上面,也就是对泛型参数的声明,可以声明为协变,或者逆变.什么 ...
- 编写高质量代码:改善Java程序的151个建议(第7章:泛型和反射___建议106~109)
建议106:动态代理可以使代理模式更加灵活 Java的反射框架提供了动态代理(Dynamic Proxy)机制,允许在运行期对目标类生成代理,避免重复开发.我们知道一个静态代理是通过主题角色(Prox ...
- 6.在MVC中使用泛型仓储模式和依赖注入实现增删查改
原文链接:http://www.c-sharpcorner.com/UploadFile/3d39b4/crud-operations-using-the-generic-repository-pat ...
- C#泛型详解(转)
初步理解泛型: http://www.cnblogs.com/wilber2013/p/4291435.html 泛型中的类型约束和类型推断 http://www.cnblogs.com/wilber ...
- C# 泛型
C# 泛型 1.定义泛型类 在类定义中包含尖括号语法,即可创建泛型类: class MyGenericClass<T> { //Add code } 其中T可以遵循C#命名规则的任意字符. ...
- java8中lambda表达式的应用,以及一些泛型相关
语法部分就不写了,我们直接抛出一个实际问题,看看java8的这些新特性究竟能给我们带来哪些便利 顺带用到一些泛型编程,一切都是为了简化代码 场景: 一个数据类,用于记录职工信息 public clas ...
- java 泛型
1.Student stu =tool.getObj();右边得到的是Object类型,需要向下转型,强转换. 2. 3. 4.泛型方法不能被静态修饰这样写 5.如果想定义定义静态泛型方法,只能这样写 ...
- Java泛型的历史
为什么Java泛型会有当前的缺陷? 之前的章节里已经说明了Java泛型擦除会导致的问题,C++和C#的泛型都是在运行时存在的,难道Java天然不支持“真正的泛型”吗? 事实上,在Java1.5在200 ...
随机推荐
- PMODB GT202 WIFI的使用
pHTTPSession = (P_HTTP_SESSION)malloc(ALIGN(sizeof(HTTP_SESSION))) PMODA/PMODB都可做WIFI使用,现介绍PMODB WIF ...
- 对DDS的深度认识
我知道,我对与电子有关的所有事情都很着迷,但不论从哪个角度看,今天的现场可编程门阵列(FPGA),都显得“鹤立鸡群”,真是非常棒的器件.如果在这个智能时代,在这个领域,想拥有一技之长的你还没有关注FP ...
- Oracle 12.1.0.2 对JSON的支持
Oracle 12.1.0.2版本有一个新功能就是可以存储.查询.索引JSON数据格式,而且也实现了使用SQL语句来解析JSON,非常方便.JSON数据在数据库中以VARCHAR2, CLOB或者BL ...
- JAVA的FileOutput/InputStream使用实例
在JAVA中,要读写文件,要使用Stream这个东西. Stream简单来说,可以看做在程序和文件之间打开了一个管道,然后把数据通过这个管道输送到文件或程序中去. FileOutput/InputSt ...
- oracle语言基础
一.语言分类 1.DML(Data Manipulation Language,数据操作语言):用于对数据的操作. DML包括:(1)SELECT:查询数据 select * from temp; ...
- deeplearning.ai 旁听如何做课后编程作业
在上吴恩达老师的深度学习课程,在coursera上. 我觉得课程绝对值的49刀,但是确实没有额外的钱来上课.而且课程提供了旁听和助学金. 之前在coursera上算法和机器学习都是直接旁听的,这些课旁 ...
- jQuery+css模拟下拉框模糊搜索的实现
html: @*输入框*@ <div> <input type="text" style="width: 85%; height: 34px;" ...
- WDCP从php5.2升级到5.3的办法,以及升级过程中iconv错误的处理
从wdcp官方论坛我们可以找到一个询问升级的帖子,然后管理员在回复中也提供了升级方法: cd /tmp wget -c http://dl.wdlinux.cn:5180/soft/php-5.3.1 ...
- 50. Pow(x, n) 幂次方
[抄题]: mplement pow(x, n), which calculates x raised to the power n (xn). Example 1: Input: 2.00000, ...
- Mock Server实践
转载自 https://tech.meituan.com/mock-server-in-action.html 背景 在美团服务端测试中,被测服务通常依赖于一系列的外部模块,被测服务与外部模块间通过R ...