C#2所搭建的核心基础(一)-泛型<一>
2012-09-04 13:23
197 查看
以下几节中我将对C#2中增加的最重要的特性进行介绍。
1)泛型---作为C#2最重要的新特性(同时也是.NET2.0的CLR中最重要的新特性),泛型实现了类型和方法的参数化。
2)可空类型---值类型没有“值不存在”的概念。有了可空类型之后,就可以表示“缺少一个有意义的值”。
3)委托---虽然委托在CLR的级别上没有任何变化,但C#2使它们使用起来更容易。除了语法得到了一些简化,匿名方法的引入,还引导我们采取更“函数化”的编程风格---这个趋势在C#3中得到了延续。
4)迭代器---虽然一直以来,都可以利用C#的foreach语句来简单地使用迭代器,但C#1中,它实现起来却是一件让人痛苦的事情。C#2编译器能在幕后帮你构建一个状态机,从而隐藏了大量复杂性。
对大多数人来说,泛型将成为C#2最重要的新特性。他们增强了性能,使代码更富有表现力,而且将大量的安全检查从执行时转移到了编译时进行。从根本上说,泛型实现了类型和方法的“参数化”,就像在普通方法调用中,经常要用参数来告诉他们使用什么值。同样,泛型的类型和方法也可以让参数告诉他们使用什么类型。
搞懂泛型的方方面面不是一件容易的事情,这样我还是通过简单的例子来学习泛型。先来看看.NET2.0提供的一个集合类:Dictionary<TKey, TValue>。
运行效果如下图:
既然我们已经看了一个例子,首先让我们来看一下Dictionary<TKey, TValue>的真正含义,什么是TKey和TValue,而且为什么要用尖括号把他们封闭起来。有两种形式的泛型:泛型类型(包括类、接口、委托和结构)和泛型方法。两者都是表示API的基本方法(不管是指一个泛型方法还是一个完整的泛型类型)。
类型参数是真实类型的占位符。在泛型声明中,类型参数要放在一对尖括号内,并且要以逗号分隔开。所以在Dictionary<TKey, TValue>中,类型参数是TKey和TValue。在使用泛型类型或方法时,需要使用真实的类型代替,这些真实的类型称为类型实参(type argument),在上述代码中类型实参是string(代替TKey)和int(代替TValue)。
如果没有为任何类型参数提供类型实参,声明的就是一个未绑定泛型类型(unbound generic type)。如果指定了类型实参,该对象就成为一个已构造类型(constructed type)。我们知道,类型(无论是否是泛型)可以看做是对象的蓝图。同样,未绑定泛型类型是已构造类型的蓝图,它是一种额外的抽象层。关系如下图:
更复杂的是,已构造类型可以是开放或封闭的。开放类型(open type)还包含了类型参数,而封闭类型(closed type)则不是开放的,类型的每个部分都是明确的。在C#代码中,唯一能看见未绑定泛型的地方(除了作为声明之外)就是在typeof操作符内。类型参数“接收”信息,类型实参“提供”信息。这个思路与方法参数/方法实参是一样的。只不过类型实参必须为类型,而不能为任意的值。只有在编译时才能知道类型实参的类型,它可以是(或包含)相关上下文中的类型参数。
读者可以具体参考下Dictionary<TKey, TValue>的内容,有助于进一步理解,这里就不做啰嗦的说明了。
泛型的发音 在向其他人描述泛型类型时,通常使用of来介绍类型参数或实参,因此List<T>读作list of T。当有多个类型参数时,可以用一个适合整个类型含义的单词来分隔他们,例如:我经常用dictionary of string to int 来强调映射的部分,而不会使用 tuple of string and int。
类型参数命名规范 虽然可以使用带有T、U和V这样的类型参数的类型,但从中根本看不出实际指的是什么,也看不出他们应该如何使用。相比之下,像Dictionary<TKey, TValue>这样的命名就好的多,TKey明显表示keys的类型,而TValue代表values的类型。如果只有一个参数类型,而且它的含义很清楚,那么一般使用T(List<T>就是一个很好的例子)。如果有多个类型参数,则应根据含义来命名,并用T前缀来指明这是一个类型参数。
1)泛型---作为C#2最重要的新特性(同时也是.NET2.0的CLR中最重要的新特性),泛型实现了类型和方法的参数化。
2)可空类型---值类型没有“值不存在”的概念。有了可空类型之后,就可以表示“缺少一个有意义的值”。
3)委托---虽然委托在CLR的级别上没有任何变化,但C#2使它们使用起来更容易。除了语法得到了一些简化,匿名方法的引入,还引导我们采取更“函数化”的编程风格---这个趋势在C#3中得到了延续。
4)迭代器---虽然一直以来,都可以利用C#的foreach语句来简单地使用迭代器,但C#1中,它实现起来却是一件让人痛苦的事情。C#2编译器能在幕后帮你构建一个状态机,从而隐藏了大量复杂性。
对大多数人来说,泛型将成为C#2最重要的新特性。他们增强了性能,使代码更富有表现力,而且将大量的安全检查从执行时转移到了编译时进行。从根本上说,泛型实现了类型和方法的“参数化”,就像在普通方法调用中,经常要用参数来告诉他们使用什么值。同样,泛型的类型和方法也可以让参数告诉他们使用什么类型。
搞懂泛型的方方面面不是一件容易的事情,这样我还是通过简单的例子来学习泛型。先来看看.NET2.0提供的一个集合类:Dictionary<TKey, TValue>。
using System; using System.Collections.Generic; using System.Text.RegularExpressions; class 泛型字典 { static Dictionary<string, int> CountWords(string text) { //创建单词到频率的新映射,它将有效统计每个单词在一段给定文本中出现的频率 Dictionary<string, int> frequencies; frequencies = new Dictionary<string, int>(); /*将文本分解成单词,对于每个单词,都检查它是否已经存在映射中, 如果是则增加现有计数;否则就为单词赋予一个初始计数1 */ string[] words = Regex.Split(text, @"\W+"); foreach (string word in words) { if (frequencies.ContainsKey(word)) { /*这里需要注意下:负责递增的代码不需要执行到int的强制类型转换,就可以执行加法运算: 取回的值在编译时已经知道是int类型。使计数递增的步骤实际是先对映射的索引器执行一次取值操作, 然后增加,然后对索引器执行赋值操作。*/ frequencies[word]++; } else { frequencies[word] = 1; } } return frequencies; } public static void Main() { Console.Write("Please input the text:"); string text = Console.ReadLine(); Dictionary<string, int> frequencies = CountWords(text); //打印映射中的每个键/值对。 foreach (KeyValuePair<string, int> entry in frequencies) { string word = entry.Key; int frequency = entry.Value; Console.WriteLine("{0}:{1}", word, frequency); } Console.Read(); } }
运行效果如下图:
既然我们已经看了一个例子,首先让我们来看一下Dictionary<TKey, TValue>的真正含义,什么是TKey和TValue,而且为什么要用尖括号把他们封闭起来。有两种形式的泛型:泛型类型(包括类、接口、委托和结构)和泛型方法。两者都是表示API的基本方法(不管是指一个泛型方法还是一个完整的泛型类型)。
类型参数是真实类型的占位符。在泛型声明中,类型参数要放在一对尖括号内,并且要以逗号分隔开。所以在Dictionary<TKey, TValue>中,类型参数是TKey和TValue。在使用泛型类型或方法时,需要使用真实的类型代替,这些真实的类型称为类型实参(type argument),在上述代码中类型实参是string(代替TKey)和int(代替TValue)。
如果没有为任何类型参数提供类型实参,声明的就是一个未绑定泛型类型(unbound generic type)。如果指定了类型实参,该对象就成为一个已构造类型(constructed type)。我们知道,类型(无论是否是泛型)可以看做是对象的蓝图。同样,未绑定泛型类型是已构造类型的蓝图,它是一种额外的抽象层。关系如下图:
更复杂的是,已构造类型可以是开放或封闭的。开放类型(open type)还包含了类型参数,而封闭类型(closed type)则不是开放的,类型的每个部分都是明确的。在C#代码中,唯一能看见未绑定泛型的地方(除了作为声明之外)就是在typeof操作符内。类型参数“接收”信息,类型实参“提供”信息。这个思路与方法参数/方法实参是一样的。只不过类型实参必须为类型,而不能为任意的值。只有在编译时才能知道类型实参的类型,它可以是(或包含)相关上下文中的类型参数。
读者可以具体参考下Dictionary<TKey, TValue>的内容,有助于进一步理解,这里就不做啰嗦的说明了。
泛型的发音 在向其他人描述泛型类型时,通常使用of来介绍类型参数或实参,因此List<T>读作list of T。当有多个类型参数时,可以用一个适合整个类型含义的单词来分隔他们,例如:我经常用dictionary of string to int 来强调映射的部分,而不会使用 tuple of string and int。
类型参数命名规范 虽然可以使用带有T、U和V这样的类型参数的类型,但从中根本看不出实际指的是什么,也看不出他们应该如何使用。相比之下,像Dictionary<TKey, TValue>这样的命名就好的多,TKey明显表示keys的类型,而TValue代表values的类型。如果只有一个参数类型,而且它的含义很清楚,那么一般使用T(List<T>就是一个很好的例子)。如果有多个类型参数,则应根据含义来命名,并用T前缀来指明这是一个类型参数。
相关文章推荐
- C#1所搭建的核心基础(二)-值类型和引用类型
- c#学习<一> 基础知识
- c#基础<一>-C#各个版本
- Android React-Native系列之<一>零基础搭建React-Native开发环境
- C# in depth ( 第二章 C#1.0所搭建的核心基础)
- Python版——博客网站<一>基础模块与框架搭建
- C#1所搭建的核心基础(一)-委托
- 黑马程序员 Java基础<一>---> java运行环境搭建
- MySQL主库已经存在的基础上搭建从库的过程--> (旧资料整理)
- <NET CLR via c# 第4版>笔记 第6章 类型和成员基础
- android基础学习<一>--->五大布局对象Framelayout,Linearlayout,Relativelayout,Tablelayout,AbsoluteLayout
- 实时开发框架Meteor基础入门系列<一>--安装与HelloWorld
- 轻松简单搭建Linux下的C#开发环境<转>
- 简单OS开发前奏<一>EDITPLUS+MASM32搭建汇编开发环境(16位+32位)
- C#制作高仿360安全卫士窗体<一>
- C#基础----Linq之List<T>篇
- UBOOT-2010-03在S3C2440上的移植<一>------------项目搭建
- OpenGL ES2.0之iOS基础<一>
- JAVA基础学习--IO流总结<一>
- 计算机网络安全基础之<一>