本文以实例形式讲述了C#泛型的用法,有助于读者深入理解C#泛型的原理,具体分析如下:

首先需要明白什么时候使用泛型:

当针对不同的数据类型,采用相似的逻辑算法,为了避免重复,可以考虑使用泛型。

一、针对类的泛型

针对不同类型的数组,写一个针对数组的"冒泡排序"。

1.思路

● 针对类的泛型,泛型打在类旁。 
● 由于在"冒泡排序"中需要对元素进行比较,所以泛型要约束成实现IComparable接口。

 class Program
{
static void Main(string[] args)
{
SortHelper<int> isorter = new SortHelper<int>();
int[] iarray = {, , , , };
isorter.BubbleSort(iarray);
foreach (int item in iarray)
{
Console.Write(item+ ", ");
}
Console.ReadKey();
}
} public class SortHelper<T> where T : IComparable
{
public void BubbleSort(T[] array)
{
int length = array.Length;
for (int i = ; i <= length -; i++)
{
for (int j = length - ; j >= ; j--)
{
if (array[j].CompareTo(array[j-]) < )
{
T temp = array[j];
array[j] = array[j - ];
array[j - ] = temp;
}
}
}
}
}

运行结果如下图所示:

2.关于泛型约束

where T : IComparable 把T约束为实现IComparable接口 
where T : class 
where T : struct 
where T : IComparable, new() 约束泛型必须有构造函数

3.关于冒泡算法

● 之所以for (int i = 0; i <= length -2; i++),这是边界思维,比如有一个长度为5的数组,如果0号位元素最终调换到4号位,每次调一个位,需要经过4次才能到4号位,即for(int i = 0; i <= 5-2, i++),i依次为0, 1, 2, 4,期间经历了4次。

● 至于for (int j = length - 1; j >= 1; j--)循环,即遍历从最后一个元素开始到索引为1的元素,每次与前一个位置上的元素比较。

4.关于比较

int类型之所以能比较,是因为int类型也实现了IComparable接口。

byte类型也一样实现了IComparable接口。

二、自定义一个类,使之也能实现冒泡算法

冒泡算法涉及到元素比较,所以自定义类必须实现IComparable接口。

 class Program
{
static void Main(string[] args)
{
Book[] bookArray = new Book[];
Book book1 = new Book(, "书一");
Book book2 = new Book(, "书二");
bookArray[] = book1;
bookArray[] = book2; Console.WriteLine("冒泡之前:");
foreach (Book b in bookArray)
{
Console.WriteLine("书名:{0},价格:{1}", b.Title, b.Price);
} SortHelper<Book> sorter = new SortHelper<Book>();
sorter.BubbleSort(bookArray);
Console.WriteLine("冒泡之后:");
foreach (Book b in bookArray)
{
Console.WriteLine("书名:{0},价格:{1}", b.Title, b.Price);
}
Console.ReadKey();
}
} public class SortHelper<T> where T : IComparable
{
public void BubbleSort(T[] array)
{
int length = array.Length;
for (int i = ; i <= length -; i++)
{
for (int j = length - ; j >= ; j--)
{
if (array[j].CompareTo(array[j-]) < )
{
T temp = array[j];
array[j] = array[j - ];
array[j - ] = temp;
}
}
}
}
} //自定义类实现IComparable接口
public class Book : IComparable
{
private int price;
private string title; public Book(){} public Book(int price, string title)
{
this.price = price;
this.title = title;
} public int Price
{
get { return this.price; }
} public string Title
{
get { return this.title; }
} public int CompareTo(object obj)
{
Book book = (Book)obj;
return this.Price.CompareTo(book.Price);
}
}

运行结果如下图所示:

三、针对方法的泛型

继续上面的例子,自定义一个类,并定义泛型方法。

 //方法泛型
public class MethodSortHelper
{
public void BubbleSort<T>(T[] array) where T : IComparable
{
int length = array.Length;
for (int i = ; i <= length - ; i++)
{
for (int j = length - ; j >= ; j--)
{
if (array[j].CompareTo(array[j - ]) < )
{
T temp = array[j];
array[j] = array[j - ];
array[j - ] = temp;
}
}
}
}
}

主程序如下:

 class Program
{
static void Main(string[] args)
{
Book[] bookArray = new Book[];
Book book1 = new Book(, "书一");
Book book2 = new Book(, "书二");
bookArray[] = book1;
bookArray[] = book2; Console.WriteLine("冒泡之前:");
foreach (Book b in bookArray)
{
Console.WriteLine("书名:{0},价格:{1}", b.Title, b.Price);
} MethodSortHelper sorter = new MethodSortHelper();
sorter.BubbleSort<Book>(bookArray);
Console.WriteLine("冒泡之后:");
foreach (Book b in bookArray)
{
Console.WriteLine("书名:{0},价格:{1}", b.Title, b.Price);
}
Console.ReadKey();
}
}

运行结果如下图所示:

另外,使用泛型方法的时候,除了按以下:

还可以这样写:

可见,泛型方法可以根据数组实例隐式推断泛型是否满足条件。

四、泛型的其它优点

1.避免隐式装箱和拆箱

以下包含隐式装箱和拆箱:

 ArrayList list = new ArrayList();
for(int i = ; i < ; i++)
{
list.Add(i); //Add接收的参数类型是引用类型object,这里包含了隐式装箱
}
for(int i = ; i < ; i++)
{
int value = (int)list[i]; //引用类型强转成值类型,拆箱
Console.WriteLine(value);
}

使用泛型避免隐式装箱和拆箱:

 List<int> list = new List<int>();
for(int i = ; i < ; i++)
{
list.Add(i);
}
for(int i = ; i < ; i++)
{
int value = list[i];
Console.WriteLine(value);
}

2.能在编译期间及时发现错误

不使用泛型,在编译期不会报错的一个例子:

ArrayList list = new ArrayList();
int i = 100;
list.Add(i);
string value = (string)list[0];

  使用泛型,在编译期及时发现错误:

List<int> list = new List<int>();
int i = 100;
list.Add(i);
string value = (string)list[0];

五、使用泛型的技巧

1.在当前文件中给泛型取别名

using IntList = List<int>;
IntList list = new IntList();
list.Add(1);

2.在不同文件中使用泛型别名,定义一个类派生于泛型

public class IntList : List<int>{}

  

C#泛型实例详解的更多相关文章

  1. java 泛型实例详解(普通泛型、 通配符、 泛型接口)

    java 泛型详解(普通泛型. 通配符. 泛型接口) 2013-02-04 19:49:49| 分类: JAVA | 标签:java |举报|字号 订阅 下载LOFTER客户端 JDK1.5 令我们期 ...

  2. Java中JSON字符串与java对象的互换实例详解

    这篇文章主要介绍了在java中,JSON字符串与java对象的相互转换实例详解,非常不错,具有参考借鉴价值,需要的朋友可以参考下 在开发过程中,经常需要和别的系统交换数据,数据交换的格式有XML.JS ...

  3. 我的书籍《深入解析Java编译器:源码剖析与实例详解》就要出版了

    一个十足的技术迷,2013年毕业,做过ERP.游戏.计算广告,在大公司呆过,但终究不满足仅对技术的应用,在2018年末离开了公司,全职写了一本书<深入解析Java编译器:源码剖析与实例详解> ...

  4. Java中JSON字符串与java对象的互换实例详解(转)

    http://www.jb51.net/article/90914.htm 在开发过程中,经常需要和别的系统交换数据,数据交换的格式有XML.JSON等,JSON作为一个轻量级的数据格式比xml效率要 ...

  5. linux基础-磁盘阵列(RAID)实例详解

    磁盘阵列(RAID)实例详解 raid技术分类 软raid技术 硬raid技术 Raid和lvm的区别 为什么选择用raid RAID详解 RAID-0 RAID-1 RAID-5 Raid-10 R ...

  6. Cocos2d-x 3.X手游开发实例详解

    Cocos2d-x 3.X手游开发实例详解(最新最简Cocos2d-x手机游戏开发学习方法,以热门游戏2048.卡牌为例,完整再现手游的开发过程,实例丰富,代码完备,Cocos2d-x作者之一林顺和泰 ...

  7. JavaScript学习笔记-实例详解-类(二)

    实例详解-类(二)   //===给Object.prototype添加只读\不可枚举\不可配置的属性objectId(function(){ Object.defineProperty(Object ...

  8. JavaScript学习笔记-实例详解-类(一)

    实例详解-类(一): //每个javascript函数(除了bind())都自动拥有一个prototype对象// 在未添加属性或重写prototype对象之前,它只包含唯一一个不可枚举属性const ...

  9. Entity Framework实例详解

    Entity Framework Code First的默认行为是使用一系列约定将POCO类映射到表.然而,有时候,不能也不想遵循这些约定,那就需要重写它们.重写默认约定有两种方式:Data Anno ...

随机推荐

  1. CPU设计学习-流水线

    各种名词 标量流水线 超级流水线 超标量流水线与多发射技术 经典五级流水线 IF |Instruction Fetch,取指 ID |Instruction Decode,译码 EX |Execute ...

  2. 1.EOS源码编译运行

    目前网络上都是针对老版EOS2.0源码编译的文章,我在mac上参考这些文章编译,最后发现根本就不对,最新版本只需一条命令(./eosio_build.sh,依赖库会自动安装的)即可.我根据这些文章手动 ...

  3. 使用truffle测试部署合约

    truffle console let contract; contract=BloggerCoin.deployed().then(instance=>contract=instanc e);

  4. GitHub把自己整个文件夹上传

    我已经有了自己github,但是我怎么对我的项目进行上传呢,普通的上传只有上传单一的文件 这不我去下载了Git(链接至机房ftp文件夹下文件ftp://10.64.130.1/%C8%ED%BC%FE ...

  5. Java实验二实验报告:java面向对象程序设计

    java实验二实验报告 实验内容 1. 初步掌握单元测试和TDD 2. 理解并掌握面向对象三要素:封装.继承.多态 3. 初步掌握UML建模 4. 熟悉S.O.L.I.D原则 5. 了解设计模式 实验 ...

  6. 进程间通信:命名管道FIFO(2)

    一.命名管道 如果我们想在不相关的进程之间交换数据,可以用FIFO文件来完成这项工作,它通常也被称为命名管道.命名管道是一种特殊类型的文件,它在文件系统中以文件名的形式存在,但是它的行为却和我们已经见 ...

  7. Linux内核策略介绍学习笔记

    主要内容 硬件 策略 CPU 进程调度.系统调用.中断 内存 内存管理 外存 文件IO 网络 协议栈 其他 时间管理 进程调度 内核的运行时间 系统启动.中断发生.系统调用以及内核线程. 进程和线程的 ...

  8. PokeCats开发者日志(十一)

      现在是PokeCats游戏开发的第六十天的上午,易版权的状态变为了待收证,但愿不久就能送到了吧.

  9. svn checkout不包括根目录

    在后面加 “.” 即可,如下: svn co svn://127.0.0.1/ylshop/ . 转载请注明博客出处:http://www.cnblogs.com/cjh-notes/

  10. jQuery的动画与特效

    显示与隐藏 show() 和 hide() 方法 动画效果的show() 和 hide() show(speed,[]callback) hide(speed,[]callback) speed:表示 ...