第 4 节 · 第一部分 基础语法

基本语法

类是图纸,里面写字段(数据)和方法(动作);new 照图纸造出对象,再调用它的方法。

时长 6:14授课计划第 1 周

学完这一节,你能

讲义

跟着视频的顺序写。每行代码都有注释,代码和运行结果都是实际运行得到的。

1类和对象

C# 是面向对象的语言:程序由一个个对象组成,互相配合着干活,同一种对象用同一个类来描述。比如矩形,有长和宽两个数,还要能接收这两个数、算出面积、再显示出来。类就像一张图纸,照着它造出来的东西才是对象。

2矩形的例子

上面是 Rectangle 类,下面的 ExecuteRectangle 类里有 Main。运行后打出三行,4.5 × 3.5 正好是 15.75:

运行结果
Length: 4.5
Width: 3.5
Area: 15.75
查看完整代码(36 行)
C#
1using System;// using 指令:引入 System 命名空间
2namespace RectangleApplication// 命名空间 RectangleApplication
3{// RectangleApplication 命名空间开始
4 class Rectangle// 声明 Rectangle 类(矩形的图纸)
5 {// Rectangle 类开始
6 // 成员变量
7 double length;// 字段 length:存长度,double 是小数类型
8 double width;// 字段 width:存宽度
9 public void Acceptdetails()// public:类外面也能调用(后面会讲);注意 d 是小写
10 {// Acceptdetails 开始
11 length = 4.5;// 长 = 4.5
12 width = 3.5;// 宽 = 3.5
13 }// Acceptdetails 结束
14 public double GetArea()// 方法 GetArea:算面积,返回一个 double
15 {// GetArea 开始
16 return length * width;// 返回 长 × 宽
17 }// GetArea 结束
18 public void Display()// 方法 Display:把三个数显示出来
19 {// Display 开始
20 Console.WriteLine("Length: {0}", length);// {0} 是占位符,换成后面的 length:Length: 4.5
21 Console.WriteLine("Width: {0}", width);// 输出 Width: 3.5
22 Console.WriteLine("Area: {0}", GetArea());// 先调用 GetArea 算出 15.75,再输出
23 }// Display 结束
24 }// Rectangle 类结束
25
26 class ExecuteRectangle// ExecuteRectangle 类,里面放 Main
27 {// ExecuteRectangle 类开始
28 static void Main(string[] args)// 程序入口 Main 方法
29 {// Main 开始
30 Rectangle r = new Rectangle();// 用 new 造出矩形对象 r,长和宽都是 0
31 r.Acceptdetails();// 长和宽变成 4.5 和 3.5
32 r.Display();// 打出三行
33 Console.ReadLine();// 等待回车(现在的 VS 不写也会停住)
34 }// Main 结束
35 }// ExecuteRectangle 类结束
36}// RectangleApplication 命名空间结束

3using 关键字

using 把一个命名空间引进来,后面就能直接用里面的类,比如 Console;一个程序里可以写好几条。程序不一定以它开头:现在新建的项目默认已经引入了 System,删掉这一行照样能运行。严格地说,它不叫语句,叫 using 指令。

C# · 第 5-7 行
5static void Main(string[] args)// Main 方法
6{// Main 开始
7 Console.WriteLine("Hello, World!");// 文件里没有 using System;,照样能用 Console
运行结果
Hello, World!

4class 和注释

class 关键字用来声明一个类,这里的类名叫 Rectangle。// 开头的是单行注释;多行注释用 /* 开头、*/ 结束。注释写给人看,编译器直接忽略。做个实验,把中间那句输出注释掉。下面这段是顶级语句写法(不写类和 Main,代码从第一行开始执行),本节最后会讲:

C# · 第 3-10 行
3/* 这个程序演示// 多行注释:/* 开头
4C# 的注释// 中间可以写好几行
5使用 */// */ 结束
6
7// 这一行是注释
8Console.WriteLine("A");// 输出 A
9// Console.WriteLine("B");
10Console.WriteLine("C");// 输出 C
运行结果
A
C

5字段和方法

C# · 第 7-9 行
7double length;// 成员变量 length,正式名字叫字段,存一个小数
8double width;// 字段 width
9public void Acceptdetails()// 成员函数,在 C# 里叫方法,写在类的大括号里

注释下面两行是矩形的数据,叫字段;再往下三个是方法:Acceptdetails 给长和宽赋值,GetArea 算面积,Display 把三个数显示出来。

6用 new 造对象

C# · 第 30-33 行
30Rectangle r = new Rectangle();// 实例化:照着图纸造出对象 r,此时长和宽都是 0
31r.Acceptdetails();// 调用 r 的方法:长 = 4.5,宽 = 3.5
32r.Display();// Display 里调 GetArea 算出面积,再打出三行
33Console.ReadLine();// 等待回车(现在的 VS 不写也会停住)

对象在内存里占一块地方,存着长和宽。

7标识符

类名、变量名、方法名都叫标识符。第一个字符只能是字母、下划线或 @,后面可以跟字母、数字和下划线;区分大小写,age 和 Age 是两个名字。

C# · 第 3-7 行
3int age = 16;// int 是整数类型;age 是合法的名字
4int Age = 17;// Age 和 age 是两个不同的名字
5int _count = 3;// 下划线开头可以
6int @if = 5;// if 是关键字,前面加 @ 就能当名字
7int Math = 8;// 和类库里的 Math 类同名,编译器也允许
运行结果
16
17
3
5
8

名字和类库里的类同名,编译器是允许的(上面的 Math 照样能跑),只是容易把人搞糊涂,最好别这么起。

数字开头(2nd)、名字中间有空格(my age)或减号(my-age)都会编译报错。@ 只能放在名字最前面,放在中间也报错:

C#
1int my@age = 16;// @ 放在了名字中间
编译报错
Program.cs(1,7): error CS1003: 语法错误,应输入“,”

名字和关键字一样也不行(前面加 @ 写成 @if 才行):

C#
1int if = 5;// if 是关键字
编译报错
Program.cs(1,5): error CS1001: 应输入标识符
Program.cs(1,5): error CS1003: 语法错误,应输入“,”

方法定义时写的是小写 d 的 Acceptdetails,调用时写成大写 D 的 AcceptDetails:

C# · 第 31 行
31r.AcceptDetails();// 大写 D 的 AcceptDetails 和 Acceptdetails 是两个名字
编译报错
Program.cs(31,15): error CS1061: “Rectangle”未包含“AcceptDetails”的定义,并且找不到可接受第一个“Rectangle”类型参数的可访问扩展方法“AcceptDetails”(是否缺少 using 指令或程序集引用?)

8关键字

关键字是 C# 预先留给自己用的词。

  • 保留关键字不能直接拿来当名字,除非前面加 @。刚才代码里的 using、class、double、public、void 都是。
  • 上下文关键字只在特定位置有特殊意思,别处可以当名字用,比如 get 和 set。现在的上下文关键字比教程里的表更多,比如 var。

9顶级语句

顶级语句是 C# 9.0 引入的写法。以前打一句 Hello World,要写命名空间、类和 Main:

查看完整代码(12 行)
C#
1using System;// 引入 System 命名空间
2
3namespace MyApp// 命名空间 MyApp
4{// MyApp 命名空间开始
5 class Program// Program 类
6 {// Program 类开始
7 static void Main(string[] args)// 程序入口 Main 方法
8 {// Main 开始
9 Console.WriteLine("Hello, World!");// 输出 Hello, World!
10 }// Main 结束
11 }// Program 类结束
12}// MyApp 命名空间结束

用顶级语句,直接在文件里写这一句就行,运行结果一模一样,都是 Hello, World!:

C#
1using System;// 引入 System 命名空间
2
3Console.WriteLine("Hello, World!");// 不写类和 Main,编译器自动生成一个 Main 把它放进去

所以写了顶级语句的文件就是程序的入口。上一节要勾“不使用顶级语句”,就是为了看到完整的 Main。

顶级语句里能写什么

常见的写法都能用:声明变量并输出、直接定义方法、用 LINQ(在 C# 里查询、筛选数据的写法,后面会讲)挑出偶数、用 try 和 catch 接住除以零的错误。这些后面会一个个细讲,现在认个脸就行:

C# · 第 12-17 行
12int Add(int a, int b) => a + b;// 直接定义方法 Add,叫局部函数;=> 后面是返回的结果
13Console.WriteLine($"Sum of 1 and 2 is {Add(1, 2)}.");// $"..." 里的 {} 会换成算出来的值:Add(1, 2) = 3
14
15// 使用 LINQ
16var numbers = new[] { 1, 2, 3, 4, 5 };// 一个整数数组
17var evens = numbers.Where(n => n % 2 == 0).ToArray();// LINQ:挑出除以 2 余 0 的数,即 2 和 4
查看完整代码(29 行)
C#
1using System;// 引入 System 命名空间
2using System.Linq;// 引入 LINQ 所在的命名空间
3
4// 顶级语句中的变量声明
5int number = 42;// 声明整数变量 number
6string message = "The answer to life, the universe, and everything is";// 声明字符串变量 message
7
8// 输出变量
9Console.WriteLine($"{message} {number}.");// $"..." 里的 {变量} 会换成变量的值
10
11// 定义和调用方法
12int Add(int a, int b) => a + b;// 局部函数 Add:返回 a + b
13Console.WriteLine($"Sum of 1 and 2 is {Add(1, 2)}.");// Add(1, 2) = 3
14
15// 使用 LINQ
16var numbers = new[] { 1, 2, 3, 4, 5 };// 一个整数数组
17var evens = numbers.Where(n => n % 2 == 0).ToArray();// 挑出偶数 2 和 4
18Console.WriteLine("Even numbers: " + string.Join(", ", evens));// 用逗号把 2、4 连起来输出
19
20// 异常处理
21try// try:试着执行下面的代码
22{// try 开始
23 int zero = 0;// zero = 0
24 int result = number / zero;// 42 除以 0,出错
25}// try 结束
26catch (DivideByZeroException ex)// catch:接住“除以零”的错误,ex 里是错误信息
27{// catch 开始
28 Console.WriteLine("Error: " + ex.Message);// 输出错误信息
29}// catch 结束
运行结果
The answer to life, the universe, and everything is 42.
Sum of 1 and 2 is 3.
Even numbers: 2, 4
Error: Attempted to divide by zero.

顶级语句写起来短,读起来清楚,适合小项目和小脚本,也能和原来的代码放在一起用。

三点注意

  1. 一个项目里只能有一个文件写顶级语句(报错里的“编译单元”就是一个 .cs 文件)。另一个文件 Other.cs 已经写了一句顶级语句 Console.WriteLine("Hi");,Program.cs 里再写:
C# · 第 3 行
3Console.WriteLine("Hello, World!");// 第二个文件里的顶级语句,编译报错
编译报错
Program.cs(3,1): error CS8802: 只有一个编译单元可具有顶级语句。
  1. 写了顶级语句的那个文件,就是程序的入口。
  2. 顶级语句里的变量只是自动生成的 Main 里的局部变量(只在 Main 里有效),同一个文件的类里用不了:
C# · 第 3-12 行
3int number = 42;// 顶级语句里的变量 number
4Console.WriteLine(number);// 这里能用:输出 42
5
6class Helper// 同一个文件里的 Helper 类
7{// Helper 类开始
8 static void Show()// Show 方法
9 {// Show 开始
10 Console.WriteLine(number);// 在类里用 number,编译报错
11 }// Show 结束
12}// Helper 类结束
编译报错
Program.cs(10,27): error CS8801: 在此上下文中,无法使用在顶级语句中声明的局部变量或本地函数“number”。

10小结

  • 类是图纸,里面有字段(数据)和方法(动作);new 照着图纸造出对象,再调用它的方法。
  • 标识符以字母、下划线或 @ 开头,@ 只能在最前面;区分大小写;关键字前加 @ 才能当名字。
  • 顶级语句由编译器包进自动生成的 Main,一个项目只能有一个文件写。

下一节:length 和 width 前面的 double,到底是什么意思?

检查题

5 道,选完马上告诉你对不对。

  1. 1Rectangle 程序运行后输出?

  2. 2new Rectangle() 刚执行完,r 的 length 是?

  3. 3哪个是合法标识符?

  4. 4把 r.Acceptdetails() 写成 r.AcceptDetails() 会怎样?

  5. 5一个项目里两个文件都写顶级语句?