c#之泛型

前言:

为什么需要泛型

因为泛型很好的避免了成员膨胀以及类型膨胀

正交性

将编程实体看成是横轴,泛型看成是纵轴的话,那么他们都会有一个交叉点。下图反应了泛型和编程实体的正交性,于是产生了泛型类,泛型接口…等等。

泛型
Yes
接口Yes
方法Yes
属性Yes
字段Yes
Yes

一,泛型解决了装箱拆箱的问题。

装修拆箱过程中需要进行大量的计算。有效的减小装箱拆箱的过程是提高性能的一个好的途径,为此微软公司提供了泛型解决方案来解决装箱拆箱引起的性能问题。
下面先通过一个例子来说明这个问题,代码如下:

namespace GenericExercise
{
    class Program
    {
        static void Main(string[] args)
        {
            RnUnbox();      //装箱拆箱的方法
            RunNoUnbox();   //采用泛型的方法

            Console.ReadLine();
        }
        
        private static void RnUnbox()
        {
            DateTime startTime = DateTime.Now; //方法开始执行时间
            ArrayList myArrayList = new ArrayList();
            for (int i = 0; i < 5; i++)
            {
                for (int count = 0; count < 5000000; count++)
                {
                    myArrayList.Add(count);  //装箱
                }
                int j = 0;
                for (int count = 0; count < 5000000; count++)
                {
                    j=(int)myArrayList[count]; //拆箱
                }
            }
            DateTime endTime = DateTime.Now;
            Console.WriteLine("使用装箱拆箱的数组--开始时间为:{0},结束时间为:{1},花费时间为{2}",startTime,endTime,endTime-startTime);
        }

        private static void RunNoUnbox()
        {
            DateTime startTime = DateTime.Now;
            List<int> myTlist = new List<int>();  //泛型数组
            for (int i = 0; i < 5; i++)
            {
                for (int count = 0; count < 5000000; count++)
                {
                    myTlist.Add(count);
                }
                int j = 0;
                for (int count = 0; count < 5000000; count++)
                {
                    j = myTlist[count]; 
                }
            }
            DateTime endTime = DateTime.Now;
            Console.WriteLine("使用泛型的数组--开始时间为:{0},结束时间为:{1},花费时间为{2}", startTime, endTime, endTime - startTime);
        }
    }
    
}

运行结果如下:
在这里插入图片描述
上述代码包括两个方法。做的都是相同的工作:将5000000条记录(int类型的数据记录)装进容器里,然后再读取出来,反复进行五次。所不同的是,RnUnbox()方法采用的是ArrayList作为容器,而RunNoUnbox()采用的是List<>作为容器。从运行时间上来看,两个方法的运行时间差别较大。这是为什么呢 ?

下面来分析一下:
public virtual int Add(object value);这是ArrayList中的Add()方法,其函数参数是object类型的,object是引用类型的。因此当我们要添加的元素是值类型的时候(比如本例),那么就会发生装箱操作。当我们读取ArrayLiist中的数据的时候,又会发生拆箱操作,因此会耗费大量时间。
第二种方法采用了 List< T > 这种泛型集合。来看看它的元素添加方法。public void Add(T item),它的函数参数是T类型的。我们在申明的时候已经将T特化成int类型了,因此,不存在装箱拆箱的过程。

泛型类

小菜,大鸟相遇了。

大鸟:一店主卖商品,他会为商品准备盒子。
小菜:现再假设一个商店卖苹果,并且,每次顾客买苹果的话,店主都会送一个盒子,创建一个苹果类,一个盒子类:

//苹果类
class Apple
{
	public string Color{get;set;}
}
//盒子类
class Box
{
	public Apple Cargo{get;set;}   //准备苹果这种货物
} 

大鸟:现在,商店里还要卖书了,而且买书的时候,店主也会提供盒子
小菜:那我就在原来的基础上,创建书的类,装书的盒子:

//苹果类
class Apple
{
	public string Color{get;set;}  //苹果的颜色
}
//盒子类,装苹果
class AppleBox
{
	public Apple Cargo{get;set;}   //准备苹果这种货物
} 

//书类
class Book
{
	public string Name{get;set;}  //书名。
}
//盒子类,装书
class BookBox
{
	public Book Cargo{get;set;}   //准备书这种货物
} 

大鸟:小菜,试想一下,如果商店还需要卖其他东西的时候,怎么办?
小菜:这个简单啊,需要什么样的盒子,我就创建什么样类型的盒子类啊。
大鸟:如果,有上千种的话, 那岂不是要创建上千个盒子类了。这就造成了类型膨胀。而且随着商品的增加,代码的改动就越来越多了。想想还有没有其他的解决方案?
小菜:我可以创建一个盒子类,然后让这个盒子可以放各种商品。代码表示如下:

//苹果类
class Apple
{
	public string Color{get;set;}  //苹果的颜色
}
//书类
class Book
{
	public string Name{get;set;}  //书名。
}
//盒子类
class Box
{
	public Apple apple{get;set;}   //准备苹果这种货物
	public Book book{get;set;}   //准备书这种货物
	//...其他商品....
} 

大鸟:这样的话,也是可以的。这段代码在显现实生活中可以这么理解:你生产了一个盒子,盒子里的空间被分成 了很多的独立空间,每个空间对应的可以存放一种商品。那么,试想一下,当你的这个盒子的一个空间用来存放苹果的话,其他人的盒子空间是空着的,这就造成了浪费。对于盒子类来说就是成员膨胀
小菜:那我该怎么呢?
大鸟:现在假设你有一个盒子,开始你是不知道这个盒子要装什么的,当决定给这个盒子贴上苹果标签的时候,那么它就是苹果盒子。当你贴上书籍标签的时候,它就是装书的盒子。
小菜:那在编程的世界里,我怎么来实现这种标签呢?
大鸟:这就是我们今天要说的泛型类了,代码如下:

//苹果类
class Apple
{
	public string Color{get;set;}  //苹果的颜色
}
//书类
class Book
{
	public string Name{get;set;}  //书名。
}
//盒子类 ( **泛型类** )
class Box<T>
{
	public T Cargo{get;set;}   //T类型的货物(泛型属性)
} 

现在来模拟一下商品交易的过程:

static void Main(string[] args)
        {
            Apple apple = new Apple() { Color="Red"};//一苹果,颜色Red
            Book book = new Book() { Name="New Book"};//一本书,名字New Book
            
            Box<Apple> box1 = new Box<Apple>() { Cargo=apple};  //苹果盒子
            Box<Book> box2 = new Box<Book>() {Cargo=book };//书盒子
            Console.WriteLine(box1.Cargo.Color);

            Console.ReadLine();
        }

这样的话,一个盒子类,一个货物属性就能满足要求了。在调用类的时候,进行盒子类型的特化
小菜:嗯呢。。。。懂了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值