《C#本质论(第4版)》一1.2 C#语法基础

    xiaoxiao2024-04-20  7

    本节书摘来异步社区《C#本质论(第4版)》一书中的第1章,第1.2节,作者: 【美】Mark Michaelis , tEric Lippert译者: 周靖 责编: 杨海玲,更多章节内容可以访问云栖社区“异步社区”公众号查看。

    1.2 C#语法基础

    C#本质论(第4版)成功编译并运行HelloWorld程序之后,我们来分析代码,了解它的各个组成部分。首先熟悉一下C#关键字以及开发者选用的标识符。

    初学者主题:关键字

    为了帮助编译器解释代码,C#中的某些单词具有特殊地位和含义,我们将其称为关键字。关键字提供了具体的语法,编译器根据这些语法来解释程序员书写的表达式。在HelloWorld程序中,class、static和void均是关键字。

    编译器利用关键字来识别代码的结构与组织方式。因为编译器对这些单词有着严格的解释,所以开发人员只能按照C#的语言规则将关键字放在特定的位置。一旦程序员违反规则,编译器就会报错。

    1.2.1 C#关键字表1-1总结了C#关键字。C# 1.0之后没有引入任何新的保留关键字,但在后续版本中,一些构造使用了上下文关键字(contextual keyword),它们在特定位置才有意义。除了那些位置,上下文关键字没有任何特殊意义。 1这样所有C# 1.0代码都完全兼容于后续的版本。2

    1.2.2 标识符和其他语言一样,C#用标识符标识程序员编写代码的构造。在代码清单1-1中,HelloWorld和Main都是标识符。分配标识符之后,以后就能用它引用所标识的构造。因此,开发人员应分配有意义的名称,不要随意分配。

    好的程序员总能选择简洁而有意义的名称,这使代码更容易理解和重用。清晰和一致是如此重要,以至于.NET Framework Guidelines建议不要在标识符中使用单词缩写3,甚至不要使用不被广泛接受的首字母缩写词。即使被广泛接受(如HTML),使用时也要一致。不要忽而这样用,忽而那样用。为避免滥用,可限制所有首字母缩写词都必须包含到术语表中。总之,要选择清晰(甚至是详细)的名称,尤其是在团队中工作,或者开发别人要使用的库的时候。

    标识符有两种基本的大小写风格。第一种风格是CLI创建者所谓的Pascal大小写(PascalCase),它在Pascal编程语言中很流行,要求标识符中每个单词的首字母大写,例如ComponentModel、Configuration和HttpFileCollection。注意在HttpFileCollection中,由于首字母缩写词HTTP的长度超过两个字母,所以仅首字母大写。第二种风格是camel大小写(camelCase),即除了第一个字母小写,其他约定与Pascal大小写风格一样,例如quotient、firstName、httpFileCollection、ioStream和theDreadPirateRoberts。

    规范

    要 更注重标识符的清晰而不是简短。

    不要 在标识符名称中使用单词缩写。

    不要使用不被广泛接受的首字母缩写词,即使被广泛接受,非必要也不要用。

    下划线虽然合法,但标识符中一般不要包含下划线、连字号或其他非字母/数字字符。此外,C#不像其前辈那样使用匈牙利命名法(为名称附加类型缩写前缀)。这避免了数据类型改变时还要重命名变量,也避免了数据类型前缀经常不一致的情况。

    在极少数情况下,有的标识符(如Main)可能在C#语言中具有特殊含义。

    规范

    要 把只包含两个字母的首字母缩写词全部大写,除非它是camel大小写风格标识符的第一个单词。

    包含三个或更多字母的首字母缩写词,仅第一个字母才要大写,除非该缩写词是camel大小写风格标识符的第一个单词。

    在 camel大小写风格标识符开头的首字母缩写词中,所有字母都 不要 大写。

    不要 使用匈牙利命名法(也就是,不要为变量名称附加类型前缀)。

    高级主题:关键字

    虽然罕见,但关键字附加“@”前缀可作为标识符使用,例如可命名局部变量@return。类似地(虽不符合C#大小写规范),可命名方法@throw()。

    在微软的实现中,还有4个未文档化的保留关键字,即arglist、 makeref、 reftype和refvalue。它们仅在罕见的互操作情形下才会用到,平时完全可以忽略。注意这4个特殊关键字以双下划线开头。C#设计者保留将来把这种标识符转化为关键字的权利。为安全起见,开发人员自己不要创建这样的标识符。

    1.2.3 类型定义

    C#中所有代码都出现在一个类型定义的内部,最常见的类型定义是以关键字class开头的。如代码清单1-2所示,类定义(class definition)是class <标识符> { ... }形式的一个代码块。

    代码清单1-2 基本的类声明

    **class** HelloWorld { _//..._ }

    类型的名称(本例是HelloWorld)可以随便取,但根据约定,它应当使用Pascal大小写风格。就本例来说,可以选择的名称包括Greetings、HelloInigoMontoya、Hello或者简单地称为Program。(对于包含Main()方法的类,Program是个很好的名称。Main()方法将在稍后详述。)

    规范

    要 用名词或名词短语命名类。

    要 为所有类名使用Pascal大小写风格。

    一个程序通常包含多个类型,每个类型都包含多个方法。

    1.2.4 Main

    初学者主题:什么是方法?

    从语法上说,C#程序中的方法是一个已命名的代码块,该代码块由一个方法声明(如static void Main())引入,后跟一对大括号({}),其中包含零或多条语句。方法可以执行计算和/或操作。与书写语言中的段落相似,方法提供了结构化和组织代码的一种方式,使之更易读。更重要的是,方法可以重用,可以在多个地方调用,所以避免了代码的重复。方法声明除了负责引入方法之外,还要定义方法名以及要传入和传出方法的数据。在代码清单1-3中,Main()后跟{ ... }便是一个C#方法的例子。

    C#程序从Main方法开始执行。该方法以static void Main()开头。在命令控制台中输入HelloWorld.exe执行程序,程序会启动并解析Main的位置,然后执行其中第一条语句,如代码清单1-3所示。

    代码清单1-3 HelloWorld分解示意图

    61458.png

    方法声明

    语句

    Main

    类定义

    虽然Main方法声明可以进行某种程度的改变,但关键字static和方法名Main是始终都是程序必需的。

    高级主题:Main方法的声明

    C#要求Main方法的返回类型为void或int,而且要么不带参数,要么接收一个字符串数组作为参数。代码清单1-4展示了Main方法的完整声明。

    代码清单1-4 带有参数和返回类型的Main方法

    **static****int** Main(**string**[] args) { _//..._ }

    args参数是一个字符串数组,用于接收命令行参数。但数组第一个元素不是程序名称,而是可执行文件名称4之后的第一个命令行参数,这一点与C和C++不同。要获取执行程序所用的完整命令,可以使用System.Environment.CommandLine。

    Main返回的int值是状态码,标识程序执行是否成功。返回非零值通常意味着错误。

    语言对比:C++/Java— main()是全部小写的

    与C风格的“前辈们”不同,C#的Main方法名使用大写M,以便与C#的Pascal大小写风格命名约定保持一致。

    将 Main方法指定为static意味着这是“静态”方法,可用“类名.方法名”的形式调用它。如果不指定static,用于启动程序的命令控制台还要先对类进行实例化(instantiation),然后才能调用方法。第5章会用一节的篇幅专门讲述静态成员。

    Main()之前的void表明该方法不返回任何数据(第2章会进一步解释)。

    C#和C/C++一样使用大括号封闭构造(如类或者方法)的主体。例如,Main方法的主体就是用大括号封闭起来的。在本例中,方法的主体只有一条语句。

    1.2.5 语句和语句分隔符

    Main方法只包含一条语句,即System.Console.WriteLine();,它在控制台上输出一行文本。C#通常用分号标识语句结束,每条语句都由代码要执行的一个或多个行动构成。声明变量、控制程序流程或者调用方法,所有这些都是语句的例子。

    语言对比:Visual Basic—基于行的语句

    有的语言以行为基本单位,这意味着不加上特殊标记,语句便不能跨行。在Visual Basic 2010以前,Visual Basic一直是典型的基于行的语言。它要求在行末添加下划线表示语句跨越多行。从Visual Basic 2010开始,行连续符在许多时候都变成可选的。

    高级主题:没有分号的语句

    C#的许多编程元素都以分号结尾。不要求使用分号的例子是switch语句。由于大括号总是包含在switch语句中,所以C#不要求语句后加上分号。事实上,代码块本身就被视为语句(它们也由语句构成),不要求以分号结尾。类似地,有的编程元素(如using指令)虽然末尾有分号但不被视为语句。

    由于换行与否不影响语句的分隔,所以可以将多条语句放到同一行,C#编译器会认为这一行包含多条指令。例如,代码清单1-5在同一行包含了两条语句。执行时,它们会在控制台窗口中分两行显示Up和Down。

    代码清单1-5 一行中包含多条语句

    System.Console.WriteLine("Up");System.Console.WriteLine("Down");C#还允许一条语句跨越多行。同样地,C#编译器会根据分号判断语句的结束位置。代码清单1-6展示了一个例子。

    代码清单1-6 一条语句跨越多行

    System.Console.WriteLine( "Hello. My name is Inigo Montoya.");

    代码清单1-6的WriteLine()语句的原始版本来自HelloWorld程序,它在这里跨越了多行。

    1.2.6 空白

    分号使C#编译器能忽略代码中的空白。除了少许例外情况,C#允许在代码中随意插入空白而不改变其语义。在代码清单1-5和代码清单1-6中,在语句中或语句间换行都可以,对编译器最终创建的可执行文件没有任何影响。

    初学者主题:什么是空白?

    空白是一个或多个连续的格式字符(如制表符、空格和换行符)。删除单词间的所有空白肯定会造成歧义。删除引号字符串中的任何空白也会。

    程序员经常利用空白对代码进行缩进来增强可读性。来看看代码清单1-7和代码清单1-8展示的两个版本的HelloWorld程序。

    代码清单1-7 不缩进

    **class** HelloWorld { **static****void** Main() { System.Console.WriteLine("Hello Inigo Montoya"); } }

    代码清单1-8 删除一切可以删除的空白

    **class** HelloWorld{**static****void** Main() {System.Console.WriteLine("Hello Inigo Montoya");}}

    虽然这两个版本看起来和原始版本颇有不同,但C#编译器认为这几个版本的代码没有任何区别。

    初学者主题:用空白来格式化代码

    为了增强可读性,利用空白对代码进行缩进是非常重要的。写代码时要遵循已经建立的编码标准和约定,以增强代码的可读性。

    本书约定每个大括号都单独占一行,并缩进大括号之间的代码。假如一对大括号之间有第二对大括号,那么第二对大括号中的所有代码也要缩进。

    这不是统一的C#标准,只是一种风格偏好。

    1.2.7 使用变量

    前面已接触了最基本的C#程序,下面让我们来声明一个局部变量。变量声明后就可以被赋值,将值替换成新值,并可在计算和输出等操作中使用。然而,变量一经声明,数据类型就无法改变。在代码清单1-9中,string max就是一个变量声明。

    代码清单1-9 变量的声明和赋值

    60347.png

    初学者主题:局部变量

    变量是一个存储位置的符号名称,程序以后可以对这个存储位置进行赋值和修改操作。局部意味着是在方法内部声明变量。

    声明变量就是定义它,需要:

    指定变量要包含的数据的类型;为它分配标识符(变量名)。

    1.2.8 数据类型

    代码清单1-9声明了string类型的变量。本章还使用了int和char。

    int是指C#的32位整型。

    char是字符类型,长度16位,足以表示无代理项的Unicode字符5。

    下一章将更详细地探讨这些以及其他常见数据类型。

    初学者主题:什么是数据类型?

    一个变量声明所指定的数据的类型称为数据类型。数据类型,或者简称为类型,是具有相似特征和行为的个体的分类。例如,animal(动物)就是一个类型,它对具有动物特征(多细胞、具有运动能力等)的所有个体(猴子、野猪和鸭嘴兽等)进行了分类。类似地,在编程语言中,类型是被赋予了相似特性的一些个体的定义。

    1.2.9 变量的声明

    在代码清单1-9中,string max是一个变量声明,它声明了一个名为max的string类型的变量。还可以在同一条语句中声明多个变量,办法是指定数据类型一次,然后用逗号分隔每个标识符,如代码清单1-10所示。

    代码清单1-10 在一条语句中声明两个变量

    string message1, message2;由于声明多个变量的语句只允许开发者提供一次数据类型,因此所有变量都具有相同类型。

    在C#中,变量名可以用任何字母或者下划线(_)开头,后跟任意数量的字母、数字和/或下划线。但根据约定,局部变量名采用的是camel大小写风格命名(即除了第一个单词,其他每个单词的首字母大写),而且不包含下划线。

    规范

    要 为局部变量使用camel大小写风格的命名。

    1.2.10 变量的赋值

    局部变量声明后必须在引用之前为其赋值。一个办法是使用=操作符,或者称为简单赋值操作符。操作符是一种特殊符号,标识了代码要执行的操作。代码清单1-11演示了如何利用赋值操作符指定变量max6和valerie要指向的字符串值。

    代码清单1-11 更改变量的值

    **class **MiracleMax { **static****void** Main() { **string** valerie; **string** max = "Have fun storming the castle!"; valerie = "Think it will work?"; System.Console.WriteLine(max); System.Console.WriteLine(valerie); max = "It would take a miracle."; System.Console.WriteLine(max); } }

    从这个代码清单可以看出,既可以在声明变量的同时对它赋值(如变量max),也可以在声明了变量之后用另一条语句赋值(如变量valerie)。要赋的值必须放在赋值操作符右侧。

    运行编译好的MiracleMax.exe程序,会生成如输出1-3所示的结果。

    输出1-3

    >MiracleMax.exe Have fun storming the castle! Think it will work? It would take a miracle.

    C#要求局部变量在读取之前“明确赋值”。此外,一次赋值会返回一个值。所以,C#允许在同一条语句中进行多个赋值操作,如代码清单1-12所示。

    代码清单1-12 赋值会返回一个值,该值可用于再次赋值

    **class **MiracleMax { **static****void** Main() { _// ..._ **string** requirements, max; requirements = max = "It would take a miracle."; _// ..._ } }

    1.2.11 变量的使用

    赋值后就能用变量标识符引用值。因此,在System.Console.WriteLine(max)语句中使用变量max时,程序在控制台上显示Have fun storming the castle!,也就是max的值。更改max的值并执行相同的System.Console.WriteLine(max)语句,会显示max的新值,即It would take a miracle.。

    高级主题:字符串不可变

    所有string类型的数据,不管是不是字符串字面量(literal)7,都是不可变的(或者说是不可修改的)。例如,不可能将字符串"Come As You Are"更改为"Come As You Age"。也就是说,不能修改变量最初引用的数据,只能重新赋值,让它指向内存中的新位置。

    1例如,在C# 2.0设计之初,语言的设计者们将yield指定成关键字。在微软发布的C# 2.0编译器的alpha版本中(该版本分发给了数千名开发人员),yield以一个新关键字的身份存在。然而,语言的设计者最终选择使用yield return而不是yield,从而避免将yield作为新关键字。除非与return连用,否则yield没有任何特殊意义。2偶尔也有不兼容的情况,比如C# 2.0要求为using语句提供的对象必须实现IDisposable接口,而不能只是实现Dispose()方法。还有一些极少见的泛型表达式,比如F(G(7));,在C# 1.0中代表F((G7)),而在C# 2.0中代表调用泛型方法G,传递实参7,结果传给F。3有两种单词缩写,一种是“Abbreviation”,比如Professor缩写为Prof.;另一种是“Contraction”,如Doctor缩写为Dr。—译者注4也就是程序名称,比如HelloWorld.exe。—译者注 5某些语言的文字编码要用两个16位值表示。第一个代码值称为“高位代理项”(high surrogate),第二个代码值称为“低位代理项”(low surrogate)。在代理项的帮助下,Unicode可以表示100多万个不同的字符。美国和欧洲地区很少使用代理项,东亚各国则很常用。—译者注6这里的max不是数学函数,而是变量名。7即literal,是指以文本形式嵌入的数据。literal有多种译法,没有一种占绝对优势。最典型的译法是“字面量”、“文字常量”和“直接量”。本书采用前者。—译者注本文仅用于学习和交流目的,不代表异步社区观点。非商业转载请注明作译者、出处,并保留本文的原始链接。

    相关资源:C#6.0本质论,Y2017M02,Chinese Edition
    最新回复(0)