代码改变世界

LINQ API的关键要素——C#3.0的新特性(一)

2010-01-11 20:37  张智清  阅读(572)  评论(0编辑  收藏  举报

隐含类型(局部)变量

隐含类型变量在C#3.0中增加了一个变量声明var,这个声明和JavaScript 的var类似,但也有不同。相同之处是它可以用var来声明任何类型的局部变量;而不同之处在于它仅仅负责告诉编译器,该变量需要根据初始化表达式来推断变量的类型,而且只能是局部变量。
为了保证使用var关键字进行声明的变量的强类型特性,C#3.0要求你必须对变量赋初值(初始化),并且放到的同一行。同样,初始化值必须是一个表达式,不能是一个对象或者collection初始化器,也不能为null。

注意:var 关键字并不意味着“变体”,也不表示该变量是松散类型化变量或后期绑定变量。它只是表示由编译器确定和分配最适当的类型

在C# 3.0中,和其他局部变量一样,数组也可以是隐式类型的。也就是说,当初始化数组时,我们可以让编译器根据初始化器的类型来推断数组类型。只要所有初始化器能隐式转换为单个类型,就可以这么做。

在C#3.0中,var 关键字只能够用在如下几个方面:

● 声明局部变量。

● 在for初始化语句中。

● 在foreach初始化语句中。

● 在using语句中。

在使用隐式类型局部变量时,必须注意如下几点:

在声明时必须同时赋值,因为声明依赖于赋值号右边的表达式。并且不能以null为初始值

● 在使用var声明一个局部变量后,它仍然具有强类型。

● 初始化器表达式的编译期类型不可以是空(null)类型,编译器无法根据null来推断出局部变量的类型。

● 初始化语句必须是一个表达式,初始化表达式不能包含它自身,但是可以是包含一个对象或集合初始化器的一个new表达式(即匿名类型)。

var的声明仅限于局部变量,但也可以包含在foreach、for、using语句中。

不能使用var来定义返回值、参数的类型或类型的数据成员。

匿名类型

在C# 3.0中,为了更加便捷的建立一种能够临时将一批具有一定关联的数据存放起来的对象,引入了新的类型,称之为匿名类型,它是C#匿名方法语法的扩展。var与new关键字一起使用时,可以创建匿名类型。匿名类型只是一个继承了object的、没有名称的类。该类的定义从初始化器中推断,类似于隐式类型化的变量。

匿名变量与隐式类型变量的区别:

● 隐式类型变量是指我们可以通过等号右边的表达式,推断出等号左边该是那种类型。

● 匿名变量则是指根据这个类型的初始化函数,我们可以推导出和创建出这个类型的实例。这两个特性很多时候是一起作用的。

匿名类型允许开发人员定义行内类型,无须显式定义类型。常和var配合使用,var用于声明匿名类型。定义一个临时的匿名类型在LINQ查询句法中非常常见,我们可以很方便的实现对象的转换和投影。

匿名类型本身有很多限制:

  • 你并没有控制匿名类型的名称。
  • 匿名类型继承System.Object。
  • 匿名类型不支持事件、自定义方法、自定义运算符和自定义重写。
  • 匿名类型是隐式封闭的(sealed) 。
  • 匿名类型的实例创建只使用默认构造函数。

扩展方法

在C#3.0中,可以把方法定义为扩展方法。简单地说,扩展方法允许现存已编译的类型(例如类、结构、接口实现)和当前即将被编译的类型(例如项目中包含扩展方法的类型)在不需要被直接更新的情况下,获得功能上的扩展。

注意:扩展方法不会真正改变编译后的代码!这种技术只是在当前应用程序的上下文中为类型增加成员。

扩展方法的定义限制:

1. 必须定义在静态类中。

2. 方法本身也必须是静态的。(记住:静态方法只可被重载overload,不可重写override!)

3. 方法的第一个参数必须是欲扩展的那个类型,比如要给int扩展一个方法,则第一个参数就必须是int。

4. 在第一个参数且仅第一个参数前面还需有一个this关键字

5. 扩展方法只能被内存中正确的实例调用,或者通过其所在的静态类被调用。

大多数情况下,扩展方法的第一个参数表示被扩展的类型。扩展方法既可以使用实例调用的方式也可以直接使用静态类调用的方式。(释疑:通过对象实例调用扩展方法只是编译器给我们的烟幕效果,其遮掩了具体真实的调用过程,其实编译器仅仅仍是以调用普通静态方法的形式进行,只把调用方法的变量作为调用参数(就是this)。)

注:不要滥用扩展方法对.NET框架基础类进行无节制的功能扩展,扩展方法有“污染性”。

扩展方法不能直接访问它扩展的类型的成员,即扩展不是继承;但是在扩展方法中可以使用this限定的参数来访问它要扩展的类型的公共成员,且仅仅是公共成员。

扩展方法受制于所处的命名空间,项目程序集中的其他命名空间都需要显式引入(即using关键字导入)扩展方法所在的命名空间以获取这些类型定义的扩展方法。

如果想在.NET代码库中公开扩展方法,定义的类型必须声明为public(我们知道,类型的默认控制访问符是internal)。