C# 学习笔记
第一个C# 程序
那么常规操作,第一步打印Hello World
1 | using System; |
这个写法是不使用顶级语句的,在C# 9.0引入了顶级语句,可以省略类和Main
方法,直接写代码
注释
接下来看注释,注释与Java类似,分为单行注释和多行注释
//
单行注释
/* ... */
多行注释
///
用于注释类、方法、属性等,可以自动生成文档,这个是C#特有的,在类、方法上面敲入三个斜杠,即可自动生成注释模板
1 | // 命名空间引用 |
控制台相关内容
现在我们主要编写控制台应用,所有得来了解了解控制台相关的东西
输入输出
WriteLine
输出并自动换行
Write
输出但不换行
ReadLine
获取输入,并自动换行,直到用户按下回车键
ReadKey
获取输入,用户按下任意键就继续执行
1 | using System; |
获取输入但不显示
如果你不希望用户输入的内容显示在控制台上,可以使用ReadKey(true)
,这样用户输入的内容就不会显示在控制台上,而是存储在KeyChar
属性中,返回为char
类型
1 | char c = Console.ReadKey(true).KeyChar; // 获取用户输入的字符,不显示在控制台上 |
清空控制台
Clear
清空控制台
1 | Console.Clear(); |
控制台窗口
设置控制台大小
SetWindowSize
设置控制台大小,参数为宽和高,单位为字符
1 | Console.SetWindowSize(80, 30); |
设置控制台缓冲区大小
SetBufferSize
设置控制台缓冲区大小,参数为宽和高,单位为字符
注意,缓冲区大小不能小于控制台大小,否则会报错
1 | Console.SetBufferSize(80, 30); |
退出控制台
Exit
退出控制台
1 | Console.Exit(0); |
光标
设置光标位置
窗口中,左上角坐标为(0,0)
,向右为X轴正方向
,向下为Y轴正方向
SetCursorPosition
设置光标位置,参数为横坐标和纵坐标,单位为字符
1 | Console.SetCursorPosition(10, 5); |
在视觉上,1y = 2x,所以要想让光标起始位置看起来像个正方形,就得将x坐标设置为y坐标的两倍
隐藏光标
CursorVisible
设置光标是否可见,参数为布尔值
1 | Console.CursorVisible = false; |
颜色
文字颜色
ForegroundColor
设置文字颜色,参数为枚举类型ConsoleColor
,默认为白色
1 | Console.ForegroundColor = ConsoleColor.Red; |
背景颜色
BackgroundColor
设置背景颜色,参数为枚举类型ConsoleColor
,默认为黑色
注意设置好背景颜色之后,需要Clear
一次,才能看到效果
1 | Console.BackgroundColor = ConsoleColor.Blue; |
折叠代码
与直接折叠大括号{}
直接的代码不同,C#提供了#region
和#endregion
来折叠代码
你可以在代码中直接使用它们来自定义你要折叠的代码块
以#region
开头,以#endregion
结尾,可以折叠代码,方便阅读
执行编译时,#region
和#endregion
会被忽略,不会影响代码的执行
1 | using System; |
数据类型
好,接下来我们来看看C#的数据类型
有符号整型
有符号整型是可正可负的
sbyte
-128~127,占用1字节
short
-32768~32767,占用2字节
int
-2147483648~2147483647,占用4字节
long
-9223372036854775808~9223372036854775807,占用8字节
1 | using System; |
无符号整型
那么顾名思义,它就是非负的整型
不过它所代表的数值的数量是和有符号整型一样的
byte
0~255,占用1字节
ushort
0~65535,占用2字节
uint
0~4294967295,占用4字节
ulong
0~18446744073709551615,占用8字节
1 | using System; |
浮点型
浮点数,即小数,它分为单精度和双精度
float
7~8位有效数字(有效数字:从第一位非零数字起算),需加f
,占用4字节
double
15~16位有效数字,写小数时,默认为此类型,其他两个的需要指定,占用8字节
decimal
28~29位有效数字,需加m
,占用16字节
1 | using System; |
字符型
char
只能存储一个字符,只能用单引号括起来,占用2字节
1 | using System; |
布尔型
bool
true/false,占用1字节
1 | using System; |
字符串
字符串类型的,一般用双引号括起来,可以存放多个字符,没有固定的占用字节数,根据内含字符的数量来决定的
string
字符串
1 | using System; |
变量初始化
一般来说,变量声明后就得初始化;亦可先定义,再初始化
1 | int a = 100; |
先定义,再初始化
1 | int a; |
但不论如何,使用变量之前必须初始化
另外,可以连续声明相同类型的变量,用逗号隔开
1 | int a = 100, b = 200, c = 300; |
变量命名规范
- 变量名必须以字母、下划线开头
- 变量名只能包含字母、数字、下划线,并区分大小写,不能重复
- 变量名不能使用关键字
- 变量名应当顾名思义
- 一般遵循驼峰命名法,即首字母小写,后续每个单词首字母大写(函数、类可采用大驼峰命名法)
常量
常量,即不可改变的量,用const
关键字定义,必须初始化,不能修改
1 | const int months = 12; |
转义字符
转义字符,即用反斜杠\
开头的字符,用于表示一些特殊字符
\n
换行\t
制表符\\
斜杠\"
双引号\'
单引号\b
光标退格\0
空字符\a
警报音
1 | Console.WriteLine("换行符\n换行"); |
类型转换
隐式转换
隐式转换为程序帮助我们转换,而不用我们手动转换
值得注意的是,数据类型——大范围装小范围
1 | int a = 10; |
在上面的例子中,a
可以隐式转换为long
类型的
但a
隐式转换为short
类型的,因为short
的范围小于int
的范围
同样的,还有以下注意事项
1 | // decimal不能隐式转换double和float,但整型可以被转换 |
显式转换
显示转为为强制转换,用括号()
变量类型 变量名 = (目标类型)变量名
但要注意的是,强制转换可能导致溢出
的问题,需要注意转换类型之间的范围
同时,其精度也有可能丢失
1 | int o = 10; |
变量类型.Parse()
方法可以将字符串转换为其他类型
1 | int q = int.Parse("123"); |
Convert.ToXXX()
方法可以更准确地转换变量类型
每一种类型都有对应的Convert.ToXXX()方法
1 | int u = Convert.ToInt32("123"); |
所有类型都可以通过ToString()
方法转换为字符串
1 | int a1 = 123; |
另外,补充说明以下,Console.ReadLine()
方法会读取用户输入的字符串,并返回一个string
类型
异常捕获
在程序运行时,有可能会出现一些错误,导致程序无法正常运行
而有时候我们需要将出现的问题输出,更为具体地通俗易懂地告诉用户出现了什么问题(毕竟报错信息并不是所有人都看得懂的)
这个情况下,我们就要使用try-catch
语句
try
语句块中,我们放置可能会出现异常的代码,而catch
语句块中,我们放置处理异常的代码
另外还有finally
语句块,无论是否出现异常,都会执行finally
语句块中的代码
1 | // 基本语法 |
运算符
赋值运算符
赋值运算符,即=
,将右边的(表达式)值赋给左边的变量
1 | int a = 10; |
不论=
右边是什么,都是先运算右边的,再赋值给左边的变量
算术运算符
就像数学中的加减乘除,在程序中也有对应的
+
加、-
减、*
乘、/
除、%
取余(即除不尽的则取它的余数,除得尽的为0)
1 | int a = 1; |
自增自减运算符
自增运算符,即++
,将变量值加1;
自减运算符,即--
,将变量值减1
但它们与变量的位置不同,结果也不同
1 | int a = 1; |
复合运算符
它是=
和算术运算符的结合,用于简化代码
+=
加等、-=
减等、*=
乘等、/=
除等、%=
取余等
1 | a += b; // 等效 a = a + b; |
关系运算符
关系运算符,用于比较两个值的大小关系,结果为bool
类型
==
等于、!=
不等于、>
大于、<
小于、>=
大于等于、<=
小于等于
1 | int h = 3; |
任意数值可以直接进行比较
但特殊类型string
、char
、bool
只能同类型
进行==
、!=
比较
逻辑运算符
逻辑运算符,用于连接多个条件,结果为bool
类型
&&
逻辑与(and)、||
逻辑或(or)、!
逻辑非(not)
1 | Console.WriteLine(a > h && b > h); |
其中,逻辑非!
的优先级最高,逻辑与&&
的优先级次之,逻辑或||
的优先级最低
位运算符
位运算符,用于对二进制位
进行操作,结果为int
类型
&
按位与、|
按位或、^
按位异或、~
按位取反、<<
左移、>>
右移
1 | int i1 = 2; |
三目运算符
表达式1 ? 表达式2 : 表达式3
如果表达式1为真,则返回表达式2的值;如果表达式1为假,则返回表达式3的值
1 | int k = 1; |
字符串拼接
字符串拼接可以用算术运算符的+
,将两个字符串连接在一起
1 | string str = "hello"; |
也可以使用{}
占位符,对字符串进行格式化,占位符中放置从0
开始的索引,表示要插入的变量
1 | string str1; |
括号
括号()
用于改变运算符的优先级,括号内的表达式先运算
1 | a = (c + d) * e; |
运算优先级(只包括上面提到的)
括号(最高优先级)
()
- 强制改变运算顺序自增/自减运算符
x++ x--
(后缀)
++x --x
(前缀)
- 算数运算符
* / %
(乘、除、取模)
+ -
(加、减)
- 位运算符
<< >>
(位移)
&
(按位与)
^
(按位异或)
|
(按位或)
关系运算符
< > <= >=
相等运算符
== !=
逻辑运算符
&&
(逻辑与)
||
(逻辑或)
- 条件运算符(最低优先级)
?:
(三元运算符)
流程控制
if语句
if
语句用于根据条件执行不同的代码块
1 | 语法: |
1 | if (true) |
if-else语句
1 | 语法: |
1 | int a = 1; |
if-else if-else语句
1 | 语法: |
1 | if (a > 5) |
switch语句
switch
类似于简化的if-else if-else语句,用于根据不同的条件执行不同的代码块
1 | 语法: |
case
判断的是表达式所得的值
是否与所写的常量值
一致,后面只能写常量,而不能写表达式或者变量
同样的,C#
的switch
语句需要写break
,不然会贯穿
即执行完一个case后,会继续执行下一个case,直到遇到break或者switch语句结束
1 | a = 100; |
while循环
while
循环用于在条件为真时重复执行代码块
但要注意,如果条件永远为真
,那么将导致死循环,直至内存溢出,程序崩溃
1 | 语法: |
1 | int i = 0; |
break
break
用于跳出循环,即当满足某个条件时,跳出循环,不再执行循环内的代码
1 | while (true) |
continue
continue
用于跳过本次循环,即当满足某个条件时,跳过本次循环,继续下一次循环
1 | int a = 0; |
do-while循环
do-while
循环与while
循环类似,但它在循环体执行完毕后,再判断条件是否为真,即无论如何都会执行一次循环体
1 | 语法: |
1 | int b = 0; |
for循环
for
循环用于在指定次数内重复执行代码块
1 | 语法: |
1 | for (int c = 0; c < 10; c++) |
实战小项目#1
需求
控制台显示一个小方块■
,用户输入w
、s
、a
、d
,控制小方块上下左右移动
实现
控制台
首先我们设置一下控制台的相关内容
1 | // 设置背景颜色 |
绘制小方块
接下来我们绘制小方块
1 | int x = 0; |
不过,对于一个游戏来说,肯定是有循环层的,不然玩家输入一次那就没了可不行
所以,我们要将绘制小方块的代码放入循环语句中,一般我们就采用while (true)
循环
1 | int x = 0; |
获取用户输入
接下来,在控制小方块移动之前,我们得先获取用户输入
1 | char c = Console.ReadKey(true).KeyChar; |
这里我们使用ReadKey(true)
不显示输入的字符,同时设置一个char c
变量来接收用户输入的字符
移动小方块
接下来,我们根据用户输入的字符,来移动小方块
那么我们输入的字符只有WASD
及wasd
8种,所以我们可以使用switch
语句来处理
1 | switch (c) |
这里我们就直接利用switch
贯穿的特性,即同一个字符的大小写都由同一块代码块来执行
随后,我们在各个case
中,根据用户输入的字符,来改变小方块的坐标
1 | switch (c) |
好,现在我们输入WASD
,小方块会根据输入的字符来移动,但是小方块不会消失,所以我们需要在每次移动之前,将小方块原来的位置清空
1 | while (true) |
擦除的话就直接写入空格即可,就可以将原来的位置的字符替换掉
限制移动范围
还没结束嘞!
当我们在在边缘位置移动小方块时,假设小方块此时贴在右边界
,而我们没注意,继续按D
(d),那么小方块就会超出控制台的范围
,导致程序崩溃
所以,在各个case
语句中,我们还得判断下一个坐标是否越界
1 | switch (c) |