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 ...
随机推荐
- mysql链接出现10060
http://www.cnblogs.com/meetrice/p/5309666.html 使用navicate链接 http://www.cnblogs.com/cxint/p/7454054.h ...
- git忽略一些提交上传的文件
在项目开发的过程中有两种文件是不需要提交的. 1.一些很重要的配置文件 包括服务器地址 账号密码 数据库密码 公私钥等等 2.一些由于开发和沙箱环境和线上环境的差异 不能使用同一个时候 需要同一个文件 ...
- FPGA噪声干扰
在FPGA高速AD采集设计中,PCB布线差会产生干扰.今天小编为大家介绍一些布线解决方案. 1.信号线的等长 以SDRAM或者DDRII为例,数据线,命令线,地址线以及时钟线最好等长,误差不要超过50 ...
- Ubuntu apt-get卸载小记
过sudo apt-get install xxxx 安装软件后,总是无法卸载干净,这里以Apache 为例,提供方法:首先sudo apt-get remove apache2再sudo apt-g ...
- NOIP2008普及组第3题 传球游戏
NOIP2008普及组第3题 传球游戏 时间限制: 1 Sec 内存限制: 128 MB提交: 29 解决: 16[提交][状态][讨论版][命题人:外部导入] 题目描述 上体育课的时候,小蛮的老 ...
- 生成器+列表生成式,生成器可以节省内存,随时调取函数运行,以及实现多线程运行函数,__next__()和.send(参数)的区别,a,b=b,a+b其实是元祖的用法,出现异常状态用try...except StopIteration来处理
列表生成式:是代码更简洁. 也可以是函数,比如func(i) 生成器:generator 列表生成式,是中括号,改成小括号,就是生成器: 如果你用列表生成式,生成一亿个数据:这里会卡好久,会生成一亿个 ...
- python下载指定页面的所有图片
实现步骤: 1.下载页面源码 2.对页面进行解析,获取页面中所有的图片路径 3.下载图片到指定路径 代码实例: # coding: utf-8 import urllib2 # 该模块用于打开页面地址 ...
- 解决JAVA_HOME nor the JRE_HOME environment variable is defined
从别的地方复制了一个tomcat, 启动后一闪即退, 使用记事本打开 startup.bat文件, 在文件底部修改, 并追加如下内容 call "%EXECUTABLE%" run ...
- Py修行路 python基础 (二十一)logging日志模块 json序列化 正则表达式(re)
一.日志模块 两种配置方式:1.config函数 2.logger #1.config函数 不能输出到屏幕 #2.logger对象 (获取别人的信息,需要两个数据流:文件流和屏幕流需要将数据从两个数据 ...
- <%@ page import=""%>的用法
转自:https://blog.csdn.net/huihui870311/article/details/455642111 <jsp:directive.page import=" ...