C# 语法基础
第一次见到 c# 程序可能会有一些奇怪,程序中有一些 {
、}
、[]
这样的符号。然而在逐渐深入了解 c# 语言的过程中,对这些符号和 c# 语言特有的其他符号会越来越熟悉,甚至会喜欢上它们。
本篇,我们继续从演示一个简单的程序示例开始,解释该程序的功能和它的各组成部分。同时,介绍一些 c# 语言的基本语法。
简单的 c# 程序示例
using system; /* 告诉编译器这个程序使用 system 命名空间中的类型 */ namespace consoleapp /* 声明一个新命名空间,名称为 consoleapp */ { class program /* 声明一个新的类类型,名称为 program */ { /// <summary> /// main 是一个特殊方法,编译器用它作为程序的起始点 /// </summary> static void main() { int number; /* 声明一个名为 number 的变量 */ // 为 number 赋值 number = 1; // 输出一行文字 console.writeline("c# 语法基础"); // 还是输出一行文字 console.writeline($"变量 number 的值是:{number}"); } } }
输出
c# 语法基础 变量 number 的值是:1
上面程序中每一行代码的作用:
第 1 行
: 告诉编译器这个程序使用 system
命名空间中的类型
第 3 行
: 声明一个新命名空间,名称为 consoleapp
- 新命名空间从第 4 行的左大括号(`{`)开始一直延伸到第 24 行与之对应的右大括号(`}`)结束 - 在这部分里声明的任何类型都是该命名空间的成员
第 5 行
: 声明一个新的类类型,名称为 program
- 任何在第 6 行和第 23 行的两个大括号中间声明的成员都是组成这个类的成员
第 10 行
: 声明一个名称为 main
的方法
- `main` 是一个特殊方法,编译器用它作为程序的起始点
第 12 行
: 声明一个名为 number
的变量
第 15 行
: 为 number
赋值
第 18 行和第 21 行
: 输出一行文字
关于 c# 的语法,要介绍的内容有很多,我们从简单的开始。
关键字
为了使编译器能够解释代码,c# 中的某些单词具有特殊地位和含义,它们称为关键字。关键字是预定义的保留标识符,对编译器有特殊意义。在上面的代码中,class
,static
和 void
均是关键字。
编译器根据关键字识别代码的结构与组织方式。由于编译器对这些单词有着严格的解释,所以必须将关键字放在特定位置。如违反规则,编译器会报错。
c# 关键字列表
abstract | as | base | bool |
break | byte | case | catch |
char | checked | class | const |
continue | decimal | default | delegate |
do | double | else | enum |
event | explicit | extern | false |
finally | fixed | float | for |
foreach | goto | if | implicit |
in | int | interface | internal |
is | lock | long | namespace |
new | null | object | operator |
out | override | params | private |
protected | public | readonly | ref |
return | sbyte | sealed | short |
sizeof | stackalloc | static | string |
struct | switch | this | throw |
true | try | typeof | uint |
ulong | unchecked | unsafe | ushort |
using | using static | virtual | void |
volatile | while |
c# 上下文关键字列表
上下文关键字用于在代码中提供特定含义,但它不是 c# 中的保留字。 一些上下文关键字(如 partial
和 where
)在两个或多个上下文中有特殊含义。
add | alias | ascending |
async | await | by |
descending | dynamic | equals |
from | get | global |
group | into | join |
let | nameof | on |
orderby | partial(类型) | partial(方法) |
remove | select | set |
unmanaged(泛型类型约束) | value | var |
when(筛选条件) | where(泛型类型约束) | where(查询子句) |
yield |
标识符
标识符是一种字符串,开发者用来命名如变量、方法、参数和许多后面将要阐述的其他程序结构。有效标识符必须遵循以下规则:
- 不得将关键字用作标识符。
- 标识符必须以字母
a-z a-z
或下划线_
符号开头。 - 标识符可以包含字母
a-z a-z
,数字0-9
和下划线_
符号。 - 标识符不得包含任何特殊字符(例如
!@ $ *.’[]
等),除了下划线_
。 - 关键字附加“
@
”前缀可作为标识符使用,例如:可命名局部变量@return
类似地,可命名方法@throw()
。
选择简洁而有意义的名称,这使代码更容易理解和重用。要选择清晰(甚至是详细)的名称,尤其是在团队中工作,或者开发要由别人使用的库的时候。
标识符区分大小写。例如,变量名 myvar
和 myvar
是不同的标识符。举个例子,在下面的代码片段中,变量的声明都是有效的,并声明了不同的整型变量。但使用如此相似的名称会使代码更易出错并更难调试,后续需要调试代码的人会很不爽。
// 语法上有效,但非常混乱 int totalcyclecount; int totalcyclecount; int totalcyclecount;
标识符的大小写规则
标识符有两种基本的大小写风格:
- pascalcasing
- camelcasing
pascalcasing 约定用于除参数名称之外的所有标识符,将每个单词的第一个字符大写(包括超过两个字母的首字母缩写),如以下示例所示:
propertydescriptor
htmltag
(在 htmltag
中, 由于首字母缩写词 html
的长度超过两个字母,所以仅首字母大写。)
这里有一种特殊情况,即遇到两个字母的首字母缩略词时,两个字母都要大写,如下面的标识符所示:
iostream
camelcasing 约定仅用于参数名称,将除第一个单词之外的每个单词的第一个字符大写,如以下示例所示。 该示例还显示,以 camelcasing 标识符开始的双字母缩写词都是小写的。
propertydescriptor
iostream
htmltag
标识符命名规范
- 要更注重标识符的清晰而不是简短。
- 不要在标识符名称中使用单词缩写。
- 不要使用不被广泛接受的首字母缩写词,即使被广泛接受,非必要也不要用。
- 不要使用下划线来区分单词,也不要在标识符中的任何位置使用下划线。
参考微软官方“框架设计准则”,链接地址:
类型定义
c# 所有代码都出现在一个类型定义的内部,最常见的类型定义以关键字 class
开头。
类型名称(本例是 program
)可以随便取,但根据约定,它应当使用 pascalcase 风格。就本例来说,可选择的名称包括 greetings
,helloinigomontoya
,hello
或者简单地称为 program
。
class program { // ... }
main
方法
main
方法是 c# 应用程序的入口点。 (库和服务不要求使用 main
方法作为入口点)。main
方法是应用程序启动后调用的第一个方法。
static void main() { // ... }
c# 要求 main
方法返回 void
或 int
, 而且要么无参,要么接收一个字符串数组。
static int main(string[] args) { // ... return 0; }
args
参数是用于接收命令行参数的字符串数组,用 system.environment.commandline
获取执行程序所用的完整命令。
main
返回的 int
是状态码,标识程序执行是否成功。返回非零值通常意味着错误。
虽然 main
方法声明可进行某种程度的变化,但关键字 static
和方法名 main
是始终都是需要的。以下是有效 main
示例:
static void main() { } static int main() { } static void main(string[] args) { } static int main(string[] args) { } static async task main() { } static async task<int> main() { } static async task main(string[] args) { } static async task<int> main(string[] args) { }
花括号、方法体和代码块
{ ... }
一般来说,所有的 c# 方法都使用花括号标记方法体的开始和结束。这是规定,不能省略。只有花括号({}
)能起这种作用,圆括号(()
)和方括号([]
)都不行。
花括号还可用于把方法中的多条语句合并为一个单元或块。
语句和语句分隔符
语句是描述一个类型或告诉程序去执行某个动作的一条源代码指令,c# 通常用分号标识语句结束。每条语句都由代码要执行的一个或多个行动构成。声明变量、控制程序流程或调用方法,所有这些都是语句的例子。
例如,下面的代码是一个由两条简单语句组成的序列。第一条语句定义了一个名称为 var1
的整型变量,并初始化它的值为 5
。第二条语句将变量 var1
的值打印到屏幕窗口。
int var1 = 5; system.console.writeline("the value of var1 is {0}", var1);
语句可以是以分号结尾的单行代码,也可以是语句块中的一系列单行语句。 语句块括在括号 {}
中,并且可以包含嵌套块。 以下代码演示了两个单行语句示例和一个多行语句块:
namespace consoleapp { class program { static void main() { // declaration statement. int counter; // assignment statement. counter = 1; // error! this is an expression, not an expression statement. // counter + 1; // declaration statements with initializers are functionally // equivalent to declaration statement followed by assignment statement: int[] radii = { 15, 32, 108, 74, 9 }; // declare and initialize an array. const double pi = 3.14159; // declare and initialize constant. // foreach statement block that contains multiple statements. foreach (int radius in radii) { // declaration statement with initializer. double circumference = pi * (2 * radius); // expression statement (method invocation). a single-line // statement can span multiple text lines because line breaks // are treated as white space, which is ignored by the compiler. system.console.writeline("radius of circle #{0} is {1}. circumference = {2:n2}", counter, radius, circumference); // expression statement (postfix increment). counter++; } // end of foreach statement block } // end of main method body. } // end of simplestatements class. }
由于换行与否不影响语句的分隔,所以可将多条语句放到同一行,c# 编译器认为这一行包含多条指令。例如,下面的代码在同一行包含了两条语句。
int var1 = 5;system.console.writeline("the value of var1 is {0}", var1);
c# 还允许一条语句跨越多行。同样地,c# 编译器根据分号判断语句结束位置。
system .console. writeline ("the value of var1 is {0}", var1);
空白
程序中的空白指的是没有可视化输出的字符,程序员在源代码中使用的空白将被编译器忽略。但使代码更清晰易读。空白字符包括:空格(space)、制表符(tab)、换行符、回车符。
例如,下面的代码段会被编译器完全相同地对待而不管它们表面上的区别。
// 推荐的格式 class program { static void main(string[] args) { console.writeline("hello world!"); } }
// 连在一起(不推荐的格式) class program {static void main(string[] args){console.writeline("hello world!");}}
为了增强可读性,用空白对代码进行缩进很有必要。写代码时要遵循制订好的编码标准和约定,以增强代码的可读性。
注释
注释,是代码中的一些“说明性文字”。注释本身不会参与程序的编译和运行,仅仅供程序员阅读。
注释分为:单行注释、多行注释、文档注释。
单行注释的符号是 2 条斜线(请注意斜线的方向),2 条斜线右侧的内容就是注释,左侧的代码不会受影响。
多行注释以“/*”开始,以“*/”结束,之间的内容就是注释,可以包含多行。
文档注释写在类、方法或属性,它的符号是 3 条斜线“///”。
/// <summary> /// xml(文档)注释 /// </summary> /// <param name="args"></param> static void main(string[] args) { // 单行注释 var item = (name: "eggplant", price: 1.99m, perpackage: 3); /* 多行注释(可以写一行,也可以写多行) */ var date = datetime.now; /* 多行注释 注释注释 注释 */ console.writeline($"on {date}, the price of {item.name} was {item.price:c2} per {item.perpackage} items."); /* * 这样比较好看 * 嗯呢,好看 * 漂亮 */ console.writeline(); console./*这是有多闲才这么写啊*/writeline(); }
编译器会忽略所有的注释,所以生成的程序集中看不到源代码中的任何注释。
总结
一门语言的语法是一套规则,用于管理语言中各有效语句组合在一起的方式。
下一篇: 正则表达式中对各字符集编码范围的总结