C# 基本概念9

来源:互联网 发布:蒙泰软件 编辑:程序博客网 时间:2024/06/06 13:22
分部类型和可空类型

分部类型可以将类、结构、接口或者方法的定义拆分为一个
或多个部分,甚至可以保存为多个源文件中。可空类型
可以用来处理值类型的值为空的情况,它能够指示可空
类型的实例是否包含一个确定的值。本章将讲解C# 语言
中的分部类型和可空类型,主要介绍以下知识点。
  声明分部类、结构和接口;
  分部类型同名成员处理;
  处理分部类型的基接口;
  可空类型的属性;
  可空类型的方法;
 bool? 类型。


分部类型

分部类型(Partial type )允许将类、结构和接口划分为多个部分
,并存储在不同的源文件中,以便于开发和维护。在Visual
Studio 2008 集成开发环境中开发应用程序时,有时一个类(如
Windows 窗体、ASP.NET 窗体页等)的一部分代码由机器自动
生成,另外一部分代码由程序员编写。如果把这个类设置为分
部类,那么这两部分代码可以保存在不同的源文件中,从而增
加了应用程序的代码的灵活性。
在声明分部类型的每一个部分时,每一个部分都必须包含partial
修饰符,并且分部类型的所有声明代码都必须位于同一命名空
间中。partial 修饰符表示它所在的类型可能还包含其他部分,
但是其他部分并不一定是必须的。如果一个类型只包含一个部
分,在声明该类型时使用了partial 修饰符,也是正确的。


声明分部类

使用partial 修饰符可以用来声明分部类。


声明分部结构

使用partial 修饰符可以用来声明分部结构。


声明分部接口

使用partial 修饰符除了可以用来声明分部类和结构之外,还
可以用来声明接口。


同名成员处理

如果一个分部类型包含了多个部分,那么该类型的所有成员
为各个部分成员的并集,并且在每一个部分中可以访问
其他部分的成员,即使在声明该成员时使用了private 修
饰符。然而,在不同部分中声明了同一个名称的成员,
则发生编译时错误。除非该成员使用了partial 修饰符。


处理基接口

如果一个分部类型包含了多个部分,那么该类型的所有基接
口集是每一个部分指定的基接口的并集。一个基接口在
分部类型的一个部分中只能指定一次,但是可以在多个
部分中同时被指定,即多个部分可以同时指定同一个基
接口。
注意:在整个分部类型中,一个基接口的成员的实现只能是
一个。但是,一个部分的基接口可以由另外一个部分提
供该基接口的实现。


可空类型

可空类型(Nullable )是一个组合了基础类型的值和布尔空
值指示符的结构。可空类型除了表示基础类型的所有值
之外,还可以表示空值(null )。可空类型为值类型,声
明可空类型存在以下两种形式。
(1 )使用System.Nullable 类声明可空类型
(2 )使用? (问号)声明可空类型


 HasValue 和 Value 属性

任何可空类型的实例都包含两个公共只读属性:HasValue
和Value 。它们的具体意义说明如下。
HasValue 属性的类型为bool ,它表示该实例是否包含一个确
定值。如果HasValue 属性的值为true ,则表示该实例包
含一个确定的值。否则,表示该实例为空,即它不包含
确定的值。此时,如果要获取该实例的值,则发生运行
时错误。
Value 属性的类型为该可空类型的基础类型,它表示该实例
的一个确定的值,并作为该实例的值。


GetValueOrDefault() 方法

可空类型的实例只包含一个方法:GetValueOrDefault() ,它
可以用来获取可空类型的实例的值或默认值。它存在以
下两种重载形式。
(1 )public T GetValueOrDefault()
(2 )public T GetValueOrDefault(T defaultValue)
T 表示可空类型的基础类型。如果可空类型的实例的
HasValue 属性的值为true ,则该方法返回该实例的值(
即Value 属性的值)。如果可空类型的实例的HasValue 属
性的值为false ,(1 )方法返回该实例的默认值,(2 )
方法返回defaultValue 参数的值。


 bool? 类型

bool? 类型为可空布尔类型,它可以表示3 个值:true 、false 和null
。可空布尔类型提供了两个运算符:& 和| 。& 运算符表示逻辑与
,| 运算符表示逻辑或。可空布尔类型的实例运算结果如表15.1 所
示。
X  Y  X & Y  X | Y
true  true  true  true
true  false  false  true
true  null  null  true
false  true  false  true
false  false  false  false
false  null  false  null
null  true  null  true
null  false  false  null
null  null  null  null


隐型变量、初始化器、匿名类型和隐型数组

隐型局部变量是使用var 关键字声明的一种隐藏类型的局部
变量。初始化器包括对象初始化器和集合初始化器,它
们分别用来初始化对象和集合。使用new 运算符和匿名对
象初始化器可以创建一个匿名类型的对象;使用var 关键
字和匿名数组初始化器可以创建一个隐型数组。
  声明隐型局部变量;
  使用隐型局部变量;
  对象初始化器;
  集合初始化器;
  匿名类型;
  隐型数组。


隐型局部变量

顾名思义,隐型(implicitly typed )局部变量是一个局部变
量,而且它的类型被隐藏了。在隐型局部变量声明中,
正被声明的局部变量的类型可以从初始化该变量的表达
式推导出来。


声明隐型局部变量

声明隐型局部变量需要使用var 关键字,并使用var 关键字作
为变量的类型。在声明隐型局部变量时,不明确指定该
变量的类型,而是使用var 关键字指定变量的类型。该变
量的实际类型将在其初始化表达式中推导出来。


使用隐型局部变量

使用隐型局部变量可以不显式指定变量的类型,从而简化了
程序代码。然而,如果大量使用隐型局部变量,往往可
能造成程序代码难以理解和阅读。因此,只有在适当的
时候使用隐型局部变量,才是一个比较好的选择。隐型
局部变量比较适合以下4 种场景。
1 .声明隐型局部变量
2 .for 语句中
3 .foreach 语句中
4 .using 语句中


对象初始化器

对象初始化器(object initializer )又称为对象初始值设定项
,它可以为某个对象的零个或多个字段或属性指定值。
即对象初始化器不显式调用该对象类型的构造函数,就
能够创建该对象类型的实例。
对象初始化器包含一组成员初始值设定项。这一组设定项由
“{” 和“}” 包围,各个设定项之间用, (逗号)分隔。每
一个成员初始值设定项都为一个赋值表达式,表达式的
左边为成员的名称,表达式的右边是一个可计算的表达
式。“ID = 1” 表达式就是一个成员初始值设定项,“{ID
= 1,Name = "Zhangsan"}” 表达式就是一组设定项。


集合初始化器

集合初始化器(collection initializer )又称为集合初始值设
定项,它可以用来设置集合中的元素。集合初始化器包
含一组元素初始值设定项。这一组设定项由“{” 和“}” 包
围,各个设定项之间用, (逗号)分隔。每一个元素初始
值设定项指定一个元素,“{1,2,3,4,5,6,7,8,9}” 表达式就是
一组元素初始值设定项。


匿名类型

顾名思义,匿名类型是一种隐藏了类型名称的类型,它由
new 运算符和匿名对象初始化器共同实现。即使用new 运
算符和匿名对象初始化器可以创建一个新的对象,这个
新创建的对象就是一个匿名类型的对象。其中,把new 运
算符和匿名对象初始化器组成的表达式又称为匿名对象
创建表达式。


隐型数组

隐型数组和匿名类型比较相似。和匿名类型的匿名对象初始
化器一样,匿名数组也存在一个匿名数组初始化器。匿
名对象初始化器一般用于创建一个匿名类型的对象,匿
名数组初始化器用来创建一个匿名数组。
匿名数组由var 关键字和匿名数组初始化器共同创建,而且
匿名数组初始化器中的元素类型都必须能够隐式转换为
同一个类型(不能为null )。即对于匿名数组初始化器而
言,会存在一种类型(不能为null ),使得该匿名数组初
始化器中所有元素都能够转换为该类型的元素。


迭代器、匿名方法和扩展方法

迭代器是一个语句块,它可以产生一系列有序值,从而使得
foreach 语句可以访问该序列。匿名方法是一种特殊的方
法,它由delegate 关键字、参数列表(可选)和包含在
“{” 和“}” 分隔符中的语句列表组成,并省略了方法的名
称。扩展方法可以向现有的类型“添加”新的方法,它
是一种静态方法,通过扩展类型的实例来调用扩展方法

  创建非泛型和泛型迭代器;
  非泛型和泛型枚举器;
  创建匿名方法;
  将匿名方法作为参数传递;
  声明扩展方法;
  调用扩展方法。


迭代器

迭代器(iterator )是一个产生(yield )有序值序列的语句
块(block )。它也可以通过yield 关键字对数组或集合类
执行自定义迭代。迭代器包含以下两个特有的语句。
yield return 语句,产生迭代的下一个值。
yield break 语句,指示迭代完成。
当迭代器执行到yield return 语句时,迭代器会保存当前位置
。如果该迭代器再一次被调用时,该迭代器将从上述保
存的位置重新开始执行。迭代器可以产生一系列的值,
而且所有值的类型均相同,该类型称为迭代器的返回类
型,又称为产生类型。


创建非泛型迭代器

IEnumerable 接口表示公开枚举数,该枚举数支持在非泛型
集合上进行简单迭代。IEnumerable 接口只包含
GetEnumerator() 方法,它返回一个循环访问集合的枚举
数。创建一个非泛型迭代器最常用的方法是实现
IEnumerable 接口的GetEnumerator() 方法。


创建泛型迭代器

如果要创建一个泛型迭代器,往往需要实现IEnumerable 和
IEnumerable<T> 接口的GetEnumerator() 方法。
C# 从入门到实践
17.1.3 IEnumerator 和 IEnumerator<T> 接口
IEnumerator 表示枚举器的非泛型接口,支持对非泛型集合
的简单迭代。IEnumerator<T> 表示枚举器的泛型接口,
支持泛型集合的简单迭代。
1 .IEnumerator 接口
2 .IEnumerator<T> 接口


匿名方法

顾名思义,匿名方法(anonymous method )是一种隐藏了
名称的方法。在C# 2.0 版本之前,声明委托的唯一方法是
使用命名方法,即方法必须指定其名称。C# 2.0 引入了匿
名方法实现了同样的功能,C# 3.0 及其以上版本,使用
Lambda 表达式(第18 章)取代了匿名方法,它比匿名方
法更加简洁。
匿名方法允许与委托关联的代码以“内联”方式写入使用委
托的位置,从而方便地将代码直接“绑定”到委托实例



创建匿名方法

匿名方法由delegate 关键字、参数列表(可选)和包含在
“{” 和“}” 分隔符中的语句列表组成。从匿名方法的组成
元素可以看到,匿名方法已经省略了该方法的名称。


将匿名方法作为参数传递

正是因为匿名方法允许与委托关联的代码以“内联”方式,
从而使得可以将匿名方法作为方法的参数来传递。


扩展方法

扩展方法可以使得开发人员能够向现有类型“添加”新的方
法,而且不需要创建新的派生类型、重新编译或以其他
方式修改原始类型。扩展方法是一种静态方法,可以通
过扩展类型的实例来调用扩展方法。


声明扩展方法

声明扩展方法时,需要使用this 修饰符。扩展方法的第一个
参数指定该方法所作用的类型,并使用this 修饰符作为该
参数的前缀。


导入扩展方法

导入扩展方法比较简单,只要使用using 指令引入扩展方法
所在的命名空间即可。实际上,被导入的扩展方法作为
其第一个参数的类型上的附加方法。


调用扩展方法

使用using 指令导入ToInt32(this string str) 扩展方法之后,就
可以调用该扩展方法了。


Lambda 表达式和查询表达式

C# 提供了一种可以用来查询集合、XML 、DataSet (数据集
)和数据库的技术,并使用Lambda 表达式和查询表达式
实现这种查询技术。Lambda 表达式其实是一种简写的匿
名函数,它可以包含表达式和C# 语句。查询表达式是一
种使用查询语法表示的表达式,它可以从一个或多个给
定的数据源中检索数据,并指定检索结果的表现形式。
Lambda 表达式; from 子句;
select 子句; where 子句;
let 子句; orderby 子句;
group 子句; into 子句;
join 子句。


Lambda 表达式

和匿名方法一样,Lambda 表达式也是一种匿名函数(
anonymous function ),它可以包含表达式和语句,并且
可用于创建委托或表达式目录树类型。但是,Lambda 表
达式比匿名方法具有更加简洁的表示形式。Lambda 表达
式可以由输入参数、Lambda 运算符和表达式(或语句块
)构成,它的语法形式如下。
(input parameters) => expression;
input parameters 表示输入参数,它是可选的;“=>” 为
Lambda 运算符(读作“goes to” );expression 表示表达
式或语句块。


输入参数

在Lambda 表达式中,输入参数是Lambda 运算符的左边部
分。它包含参数的数量可以为0 ,1 或者多个。当输入参
数的数量为0 时,Lambda 表达式的左边部分的一对小括
弧不能被省略。


表达式或语句块

在Lambda 表达式中,Lambda 运算符的右边部分可以是一
个表达式或由多个表达式组成的语句块。


查询表达式

查询表达式(Query expression )是一种使用查询语法表示
的表达式,由一组类似与SQL 或XQuery 的声明性语法编
写的子句组成。每一个子句可以包含一个或多个C# 表达
式,这些C# 表达式本身也可能是查询表达式或包含查询
表达式。查询表达式包括8 个基本子句,具体说明如下。
from 子句 select 子句
where 子句 let 子句
orderby 子句 group 子句
into 子句 join 子句
查询表达式必须以from 子句开头,以select 或group 子句结束
。在第一个from 子句和最后一个select 子句或group 子句
之间,可以包含一个或多个where 子句、let 子句、join 子
句、orderby 子句和group 子句,甚至还可以是from 子句



from 子句

任何一个查询表达式,不管是否为子查询表达式,它必须包
含from 子句,且以from 子句开头。from 子句用来指定查
询表达式的数据源和范围变量。数据源不但可以包括查
询本身的数据源,而且还可以包括子查询的数据源。范
围变量用来表示数据源序列中的每一个元素。
1 .数据源
2 .包含单个from 子句的查询表达式
3 .包含多个from 子句的查询表达式
4 .包含复合from 子句的查询表达式


select 子句

select 子句指定查询结果的类型和表现形式,即指定将在执
行查询时产生的值的类型。select 子句结果及其表现形式
与其前面所有子句的计算结果,以及本身中的所有表达
式相关。一个查询表达式要么以select 子句结束,要么以
group 子句结束。


 where 子句

where 子句指定筛选元素的逻辑条件,即用来确定从查询表
达式中选择哪些元素。where 子句由一个或多个布尔表达
式,以及逻辑运算符(如逻辑与、逻辑或等)组成。一
个查询表达式可以包含一个或多个where 子句。在查询表
达式中,where 子句不能出现在查询表达式的第一个子句
或最后一个子句的位置,其他任何位置都可以放置where
子句。


let 子句

let 子句可以创建一个新的范围变量,用来保存查询表达式中
的中间结果。let 子句创建的范围变量是一个只读变量,
它的值只能通过初始化操作赋值。一旦设定了范围变量
的值之后,它的值将不能被修改。当然,可以查询该范
围变量的值。


orderby 子句

orderby 子句可以对查询结果进行排序,排序方式为“升序
”(由ascending 关键字指定)和“降序”(由descending
关键字指定)。


group 子句

group 子句(使用by 关键字)可以对查询的结果进行分组,
并返回元素类型为IGrouping<TKey, TElement> 的序列。
其中,TKey 为分组中键的类型,TElement 为分组中元素
的类型。


into 子句

into 子句可以创建一个临时标识符,并用来保存group 子句
、join 子句或selet 子句的结果,以供其他子句查询该结果
。有时,称在group 或select 子句中使用新标识符的用法为
“延续”。


join 子句

join 子句是查询表达式中比较复杂的一个子句,它和SQL 语
句中的JOIN 子句比较相似,可以用来联接两个数据源,
即设置两个数据源之间的关系。一般情况下,这两个数
据源是存在相关联的属性或值,以供这两个数据源中的
元素进行比较。特别地,join 子句可以使用equals 关键字
比较元素的指定属性是否相等。join 子句支持以下3 种常
见联接方式。
  内部联接,元素的联接关系必须同时满足两个数据源,
类似于SQL 语句中的INNER JOIN 子句。
  分组联接,包含into 子句的join 子句。
  左外部联接,元素的联接关系必须满足联接中的左数据
源,类似于SQL 语句中的LEFT JOIN 子句。
原创粉丝点击