为什么要有泛型?

请大家思考一个问题:由你来实现一个最简单的冒泡排序算法。假设没有使用泛型的经验。可能会毫不犹豫的写出下面代码:

public class SortHelper
{
//參数为int数组的冒泡排序
public void BubbleSort(int[] array)
{
int length = array.Length; for (int i = 0; i <= length - 2; i++)
{
for (int j = length - 1; j >= 1; j--)
{
//对两个元素进行交换
if (array[j] < array[j - 1])
{
int temp = array[j];
array[j] = array[j - 1];
array[j - 1] = temp;
}
}
}
}
}

如今通过对这个程序进行一个简单的測试:

      static void Main(string[] args)
{
#region 没有泛型前的演示
SortHelper sorter = new SortHelper(); int[] arrayInt = { 8, 1, 4, 7, 3 }; //对int数组排序
sorter.BubbleSort(arrayInt); foreach (int i in arrayInt)
{
Console.Write("{0} ", i);
} Console.ReadLine();
#endregion
}

我们发现它执行良好,欣喜的觉得这便是最好的解决方式了。直到不久后,须要对一个byte类型的数组进行排序。而上面的排序算法仅仅能接受一个int类型的数组。C#是一个强类型的语言。无法在一个接受int数组类型的地方传入一个byte数组。只是没关系,如今看来最快的解决方法是把代码复制一遍,然后将方法的签名改一下:

 public class SortHelper
{
//參数为byte数组的冒泡排序
public void BubbleSort(byte[] array)
{
int length = array.Length; for (int i = 0; i <= length - 2; i++)
{
for (int j = length - 1; j >= 1; j--)
{
//对两个元素进行交换
if (array[j] < array[j - 1])
{
byte temp = array[j];
array[j] = array[j - 1];
array[j - 1] = temp;
}
}
}
}
}

好了,再一次解决这个问题。可通过认证观察我们发现,这两个方法除了传入的參数类型不同外。方法的实现非常相似,是能够进行进一步抽象的。于是我们思考,为什么在定义參数的时候不用一个占位符T取代呢?T是Type的缩写。能够代表不论什么类型,这样就能够屏蔽两个方法签名的差异:    

   public class SortHelper<T>
{
//參数为T的冒泡排序
public void BubbleSort(T[] array)
{
int length = array.Length; for (int i = 0; i <= length - 2; i++)
{
for (int j = length - 1; j >= 1; j--)
{
//对两个元素进行交换
if (array[j] < array[j - 1])
{
T temp = array[j];
array[j] = array[j - 1];
array[j - 1] = temp;
}
}
}
}

通过代码我们能够发现,使用泛型极大的降低了反复代码,使代码更加清爽。

泛型类就类似于一个模板,能够再须要时为这个模板传入不论什么须要的类型。如今更专业些,为占位符T起一个正式的名称。在.Net中叫做“类型參数”。

类型參数约束

实际上,如果执行上面的代码就会发现,它连编译都通只是去,为什么呢?考虑这样一个问题:如果我们自己定义一个类型。名字叫做Book,它包括两个字段:一个是int类型的Price代表书的价格;一个是string类型的Title,代表书的标题:

public class Book
{
//价格字段
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 Titie
{
get { return this.title; }
}
}

如今创建一个Book类型的数组,然后使用上面定义的泛型类对它进行排序,代码应该像以下这样:

            Book[] bookArray = new Book[2];

            Book book1 = new Book(30, "HTML5解析");
Book book2 = new Book(21, "JavaScript实战"); bookArray[0] = book1;
bookArray[1] = book2; SortHelper<Book> sorterGeneric = new SortHelper<Book>();
sorterGeneric.BubbleSort(bookArray); foreach (Book b in bookArray)
{
Console.WriteLine("Price:{0}", b.Price);
Console.WriteLine("Title:{0}", b.Titie);
}

这时问题来了。既然是排序。就免不了比較大小,那么如今请问:book1和book2谁比較大?张三能够说book1大,由于它的Price是30,;而李四能够说book2大,由于它的Title是“J”开头的,比book1的“H”靠后。说了半天,问题在于不确定按什么规则排序。

  既然不知道,那我们就给Book定义一种排序规则(按价格排序),我们声明一个用于比較的接口:

 public interface IComparable
{
int CompareTo(object obj);
}

让Book类型实现这个接口:

public class Book : IComparable
    {
        //CODE:上面的实现略
        public int CompareTo(object obj)
        {
            Book book2 = (Book)obj;
            return this.Price.CompareTo(book2.Price);
        }
    }

既然我们如今已经让Book类实现了IComparable接口,那么泛型类应该可以工作了吧?不行的,还要记得,泛型类是一个模板类。它对在运行时传递的类型參数是一无所知的。也不会做不论什么的推測。所以须要我们告诉泛型类SortHelper<T>,它所接受的T类型參数必须可以进行比較,也就是说必须实现IComparable接口。我们把对T进行约束这样的行为称:泛型參数约束。

为了要求类型參数T必须实现IComparable接口,须要像以下这样又一次定义:

public class SortHelper<T> where T : IComparable
{
//參数为T的冒泡排序
public void BubbleSort(T[] array)
{
int length = array.Length; for (int i = 0; i <= length - 2; i++)
{
for (int j = length - 1; j >= 1; j--)
{
//对两个元素进行交换
if (array[j].CompareTo(array[j - 1]) < 0)
{
T temp = array[j];
array[j] = array[j - 1];
array[j - 1] = temp;
}
}
}
}
}

上面的定义说明了类型參数T必须实现IComparable接口。否则将无法通过编译。由于如今T已经实现了IComparable接口,而数组array中的成员是T的实例。所以当在array[i]后面点击小数点“.”时,VS能够智能提醒出T是IComparable的成员,也就是CompareTo()方法。

深入理解C#中的泛型(一)的更多相关文章

  1. 十分钟教你理解TypeScript中的泛型

    转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者.原文出处:https://blog.bitsrc.io/understanding-generics-in-t ...

  2. 夯实Java基础系列13:深入理解Java中的泛型

    目录 泛型概述 一个栗子 特性 泛型的使用方式 泛型类 泛型接口 泛型通配符 泛型方法 泛型方法的基本用法 类中的泛型方法 泛型方法与可变参数 静态方法与泛型 泛型方法总结 泛型上下边界 泛型常见面试 ...

  3. 6.在MVC中使用泛型仓储模式和依赖注入实现增删查改

    原文链接:http://www.c-sharpcorner.com/UploadFile/3d39b4/crud-operations-using-the-generic-repository-pat ...

  4. Java中的泛型 (上) - 基本概念和原理

    本节我们主要来介绍泛型的基本概念和原理 后续章节我们会介绍各种容器类,容器类可以说是日常程序开发中天天用到的,没有容器类,难以想象能开发什么真正有用的程序.而容器类是基于泛型的,不理解泛型,我们就难以 ...

  5. 5.在MVC中使用泛型仓储模式和工作单元来进行增删查改

    原文链接:http://www.c-sharpcorner.com/UploadFile/3d39b4/crud-operations-using-the-generic-repository-pat ...

  6. 窥探Swift之使用Web浏览器编译Swift代码以及Swift中的泛型

    有的小伙伴会问:博主,没有Mac怎么学Swift语言呢,我想学Swift,但前提得买个Mac.非也,非也.如果你想了解或者初步学习Swift语言的话,你可以登录这个网站:http://swiftstu ...

  7. 转载:C#中的泛型

    泛型(generic)是C#语言2.0和通用语言运行时(CLR)的一个新特性.泛型为.NET框架引入了类型参数(type parameters)的概念.类型参数使得设计类和方法时,不必确定一个或多个具 ...

  8. C#中的泛型

    写在前面:好几个月没更新了,这些天换了份工作,原来的公司出了很多事所以辞职了.这篇文章写的超级好,让我终于明白了困扰在我心里好久的C#泛型的概念,不仅收藏了,还手动转发一下 哈哈哈~ 1.1 C#中的 ...

  9. C#中的泛型 【转】

    C#中的泛型 泛型(generic)是C#语言2.0和通用语言运行时(CLR)的一个新特性.泛型为.NET框架引入了类型参数(type parameters)的概念.类型参数使得设计类和方法时,不必确 ...

随机推荐

  1. OpenStack 镜像服务 Glance部署(七)

    创建虚拟机我们需要有glance的支持,因为glance是提供镜像的服务. Glance有两个比较重要的服务: Glance-api:接受云系统镜像的构建.删除.读取请求 Glance-Registr ...

  2. LintCode 13. Implement strStr()

    LintCode 13. Implement strStr() 题目描述 对于一个给定的 source 字符串和一个 target 字符串,你应该在 source 字符串中找出 target 字符串出 ...

  3. CodeVS1169 传纸条 [DP补完计划]

    题目传送门 题目描述 Description 小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题.一次素质拓展活动中,班上同学安排做成一个m行n列的矩阵,而小渊和小轩被安排在矩阵对角线的两端, ...

  4. 洛谷P3805 [模板]Manacher算法 [manacher]

    题目传送门 题目描述 给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度. 字符串长度为n 输入输出格式 输入格式: 一行小写英文字符a,b,c...y,z组成的字符 ...

  5. bash 中的变量可以这么用

    举个例子: t.sh ====================== #!/bin/bash ./a.sh ./b.sh ======================= a.sh =========== ...

  6. Xamarin XAML语言教程模板视图TemplatedView(二)

    Xamarin XAML语言教程模板视图TemplatedView(二) (2)打开MainPage.xaml文件,编写代码,将构建的控件模板应用于中TemplatedView.代码如下: <? ...

  7. 洛谷P1113 杂务

    题目描述 John的农场在给奶牛挤奶前有很多杂务要完成,每一项杂务都需要一定的时间来完成它.比如:他们要将奶牛集合起来,将他们赶进牛棚,为奶牛清洗乳房以及一些其它工作.尽早将所有杂务完成是必要的,因为 ...

  8. AGC 012 D - Colorful Balls

    题面在这里! 为什么atcoder都是神仙题啊qwq 首先发现如果要让 x,y 互换位置的话,要么通过他们直接换 (也就是x和y满足两种操作之一),要么间接换,通过一些其他的元素形如 x可以和 a[1 ...

  9. 【DFS】【打表】Lattice Animals

    [ZOJ2669]Lattice Animals Time Limit: 5 Seconds      Memory Limit: 32768 KB Lattice animal is a set o ...

  10. 【深度优先搜索】mr353-取奶

    应该是USACO的题目,暂时没有找到对应出处. [题目大意] 农夫约翰要量取 Q(1 <= Q <= 20,000)夸脱(夸脱,quarts,容积单位——译者注) 他的最好的牛奶,并把它装 ...