文章目录
1. 介绍
C# vs .Net
什么是C#和.Net?
C#是编程语言,.Net
是一个用于开发构建Windows程序的框架,它包括公共语言运行时(Commo Lauguage Runtime,CLR)和类库(Class Library)。
C#和.Net有什么用途?
C#作为一门面向对象高级语言,可以让我们很方便的编写各种程序代码。.Net
则拓展了C#本身的功能,提供更强大的拓展代码以及有效的运行时处理。
参考链接:
什么是 CLR ?
公共语言运行时 (CLR) 概述 - .NET | Microsoft Learn
1.1 C#程序结构
什么是程序结构?
程序结构是一门语言最基础的代码结构,他是一个书写程序的模板框架。其中C#的程序结构包含以下几种:
- 类(Class):C#中最基础的结构是类,一个类由属性(字段)及方法(函数)构成,一个类通常负责一个功能。C# 类型系统中的类。 - C# | Microsoft Learn
- 命名空间(Namespace):命名空间是一系列相关类的容器,如对图像处理的命名空间、对数据处理的命名空间等。整理命名空间中的类型 - C# | Microsoft Learn
- 程序集(Assembly):程序集则负责管理相关的命名空间,保证程序安全性,他的物理表现为DLL或exe。
- 程序应用(Application):在对所写的代码进行编译连接生成可执行的应用,它通常会包含数个程序集。
程序结构有什么用?
熟悉程序结构能让我们对自己所写程序的构成有一个细致地了解,并且在很大程度上也对我们编写程序时不同代码所书写的位置起到一种规范性作用。
1.2 Visual Studio中的项目结构
什么是项目结构?
如同程序结构,每个项目也有他自己的一个功能分类的结构,对我们代码所处位置、资源文件所处位置等进行了详细划分。Visual Studio中的项目划分为了以下几个板块:
- 解决方案:项目结构中最顶层的为解决方案,解决方案只是一个容器,用于包含一个或多个相关项目,以及生成信息、Visual Studio 窗口设置和不与特定项目关联的任何杂项文件。
- 项目:项目包含所有编译为可执行文件、库或网站的文件。 这些文件可以包括源代码、图标、图像、数据文件等。 除此之外,项目还包含编译器设置以及程序与各种服务或组件通信可能需要的其他配置文件。
- 项目属性配置(Properties):该目录包含了对项目的相关属性设置,其中对项目的描述、版本等内容保存在
Assemblylnfo.cs
文件中。 - 引用(References):它包含了一系列项目中所使用的程序集依赖。
- 项目配置(App.config):包含对项目的设置如编译版本等。
- 代码文件
.cs
:即我们进行代码书写的地方。
一定要按照这个板块划分进行程序书写吗?
在编写程序时建议按照统一规范进行划分编码,这样程序结构更具有规范性,也更加方便我们自己和他人读懂项目。
参考链接:什么是 Visual Studio 解决方案和项目? - Visual Studio (Windows) | Microsoft Learn
1.3 一个代码文件的基本结构
什么是代码的基本结构?
代码文件的基本结构是书写该语言代码的基础框架,他对我们在什么地方可以写什么样的代码进行了详细划分。一个代码文件模板形如以下样式:
//命名空间引用
using System; //C# 应用程序的基本命名空间,包含了C#程序所需的所有基本类和基类
//命名空间,名称具有唯一性,不可重复,在同一个命名空间内可以访问该命名空间的所有类
namespace WindowsApp1 //命名空间,名称为WindowsApp1
{
//C#类
class Program
{
//函数,包含访问权限、返回值、函数名、参数等
static void Main(string[] args) //主函数,应用程序入口函数
{
}
}
}
以定要按照这个结构书写代码吗?
除开部分可选内容外,其他必须严格按照该结构进行书写,否则会出现报错编译失败等问题。
参考链接:C# 程序结构 | 菜鸟教程 (runoob.com)
1.4 标识符
什么是标识符?
标识符是我们对函数、变量等命名的符号名称,它指向该函数或变量在硬盘中的具体地址以便于我们对它进行操作。
怎么对标识符进行命名?
C#中常用的标识符命名方法包含两种:
- 小驼峰命名:作为标识符的单词首个单词全小写,后续单词首字母大写,通常用于给变量命名,如
firstName
。 - 大驼峰命名:所有单词首字母均大写,通常用于命名常量,如
FirstName
。
1.5 关键字
什么是关键字?
C#关键字是C#中预定义的保留字符,它代表了C#中的一些编译功能或语法结构。
关键字可以作为标识符使用吗?
关键字代表着编程语言的一些编译功能和语法,从另一个角度讲他也是一个固定的语法或功能的标识符,所以它不能直接作为我们编码时的标识符使用(即对函数、类等的命名),例如在命名时对一个整型不能直接命名为int
,但我们可以命名为intValue
或@int
等。
具体关键字参考:C# 关键字 | Microsoft Learn
2. C#变量(Variables)与常量(Constants)
2.1 变量与常量的基本概念
什么是变量?
变量是我们手动名命名的一个供程序操作的存储区的名字,是用于存储和表示数据的标识符。每个变量都有一个特定的类型,类型决定了变量的内存大小和布局,范围内的值可以存储在内存中,可以对变量进行一系列操作。
如何使用变量?
创建变量的基本语法为(访问权限) 变量类型 变量名( = 初始值);
,具体语法见后文。注意,标识符不能以数字开头,不能在其中包含空格。
在声明变量时,您需要指定变量的类型,并且可以选择性地为其分配一个初始值。
参考链接:C# 变量 | 菜鸟教程 (runoob.com)
什么是常量?
常量也是一个指向存储区的标识符,不同的是它所指向的存储区无法被修改,只允许读取。
如何定义常量?
常量与变量基本相同,但它的值必须在创建时进行赋值,且在程序运行时不可以被修改,只能在编码时手动进行修改。
常量创建的基本语法为在变量类型前加上const
关键字。
参考链接:C# 常量 | 菜鸟教程 (runoob.com)
2.2 常见数据类型
什么是数据类型?
在自然语言中我们详细的划分了语句、文字、数字、符号等,在计算机中也对这些内容进行了详细的划分,便于计算机理解我们所需要或所使用的数据是什么、怎么处理等等的问题,这就是数据类型。
必须使用吗?
在C#中,数据类型无处不在,基础的输入输出使用的Console
是特殊数据类型类class
,控制台打印的文字是字符串String
,在编码中我们随时都在跟各种各样的数据打交道,不用是不行滴。
有哪些数据类型?
常用数据类型分为以下几种:
整型:代表自然语言中的整数
C#类型 | .Net类型 | 描述 | 范围 | 默认值 |
---|---|---|---|---|
sbyte | SByte | 8 位有符号整数 | -27~27-1(-128 到 127) | 0 |
byte | Byte | 8 位无符号整数 | 0~28-1(0 到 255) | 0 |
short | Int16 | 16 位有符号整数类型 | -215~215-1(-32,768 到 32,767) | 0 |
ushort | UInt16 | 16 位无符号整数类型 | 0~216(0 到 65,535) | 0 |
int | Int32 | 32位有符号整数类型 | -231~231-1(-2,147,483,648 到 2,147,483,647) | 0 |
uint | UInt32 | 32位无符号整数类型 | 0~232(0 到 4,294,967,295) | 0 |
long | Int64 | 64为有符号整数类型 | -263~263-1(-9,223,372,036,854,775,808 到 9,223,372,036,854,775,807) | 0 |
ulong | UInt64 | 64为无符号整数类型 | 0~264(0 到 18,446,744,073,709,551,615) | 0 |
浮点型:代编自然语言中的小数
C#类型 | .Net类型 | 描述 | 范围 | 默认值 |
---|---|---|---|---|
float | Float | 32 位单精度浮点型 | -3.4 x 1038 到 + 3.4 x 1038 | 0.0f |
double | Double | 64 位双精度浮点型 | (+/-)5.0 x 10-324 到 (+/-)1.7 x 10308 | 0.0d |
decimal | Decimal | 128 位精确的十进制值,28-29 有效位数 | (-7.9 x 1028 到 7.9 x 1028) / 100 到 28 | 0.0m |
注意:浮点型直接赋值数字时,数字后面必须加上对应类型的标识符(f,d,m),否则会按照默认类型double处理。
布尔类型:用于判断逻辑正误的数据类型,常用于逻辑判定语句中
C#类型 | .Net类型 | 描述 | 范围 | 默认值 |
---|---|---|---|---|
bool | Boolean | 布尔值(占1个字节8位) | True和False(1和0) | False(0) |
字符型:代表我们自然语言中的单个文字
C#类型 | .Net类型 | 描述 | 范围 | 默认值 |
---|---|---|---|---|
char | Char | 16 位 Unicode 字符 | U +0000 到 U +ffff | ‘/0’ |
参考链接:Types - C# language specification | Microsoft Learn
2.3 数据溢出
什么是数据溢出?
数据溢出是由于计算机数据存储问题导致的在操作数据时产生的数据越界。
计算机中数据是怎么存储的?
在计算机中,数据并非像我们肉眼所见的形式进行存储,而是通过二进制进行储存,例如前面所提到的byte
类型,自然语言中它的大小为 0 到 255 ,但是更加符合计算机中的形式表达应该为 00000000
到11111111
。
计算二进制数的值的方式即为从右到左依次记为2的n次方,其中n为位数-1,若该位为1则进行相加,不为1则不进行计算,例如1010
他的值为0*20+1*21+0*22+1*23,即10.
而对于有符号类型数据,最高位为符号位(即最左边的二进制数),若为1则为负数,而他的值的计算则涉及到补码及反码的知识(二进制数的原码、反码、补码(详解))。
如何理解溢出?
因为在计算机中数据长度是固定的,所以在已经达到最大值时若我们还对他进行+
操作,将会导致数据溢出,例如byte最大为11111111(255)
,如果在对其进行+1操作,它的值理应变为1 00000000
,但因为长度仅有8位,所以会将高位抛弃,数值变为00000000
。
数据溢出将会对内存产生严重影响,严重时会导致程序及系统崩溃。
如何检查是否存在数据溢出?
可以使用**checked
检测数据溢出**。因为在编译时,编译器并不会检测到数据的溢出(溢出发生在执行到该语句的时候),所以如果不确定自己的操作是否会导致数据溢出的话,可以使用checked
语句包裹操作的代码,他将会在发生溢出时抛出异常。
byte data = 255;
checked
{
data += 1; //发生未经处理的异常:System.OverflowException:“Arithmetic operation resulted in an overflow.”
}
2.4 类型转换(Type Conversion)
什么是类型转换?
在实际编码中进行数据处理等行为时,通常会存在将小数作为整数处理、将字符串拆分为单个字符处理的情况,这些情况下的转换就是类型转换。
有哪些类型转换?
在编码过程中,通常会有对数据类型进行转换的情况,其中分为三类:隐式转换(Implicit Type Conversion)、显示转换(Explicit Type Conversion)、不兼容数据类型转换(Non-compatible Types Conversion)。
隐式转换(Implicit Type Conversion)
什么是隐式转换?
隐式转换是在不经意之间发生的转换,如我们创建了一个short变量,而在后续操作中我们将它与一个int变量进行运算并复制给int变量时,发生了将short隐式转换为int的过程。
通常什么情况下会发生隐式转换?
-
小数据转换为大数据:在发生隐式转换时,如果将小数据转换为大数据(如short转换为int),编译器通常不会进行提示,而是将小数据所包含的数直接赋值给大数据类型,而对于缺少的高位数字则全部补为小数据的符号位。
short a = 255; int b = a; //b的值为255,二进制为00000000 00000000 00000000 01111111
-
大数据转换为小数据:将一个大数据转换为小数据,编译器将直接报错,除非我们使用显式强制数据类型转换。
int b = int.MaxValue; short c = b;//错误:无法将类型“int“隐式转换为"short”。存在一个显式转换(是否缺少强制转换?)
显示转换(Explicit Type Conversion)
什么是显示转换?
显式转换也叫强制数据转换,他是我们在需要处理数据时手动进行的数据类型转换。
为什么要使用强制数据转换?
在实际开发中,我们可能需要将某一个数据强制转换为一个较小数据类型,这个时候使用强制数据转换可以避免编译报错,同时也能得到我们预期的结果。
如何进行强制转换?
强制转换在被转换类型前用括号写入目标转换类型即可,举例如下:
int b = int.MaxValue;
short c = (short)b;//编译通过,可以运行
但是需要注意的是,强制转换后小数据只会截取对应位数的二进制码,比如上面的代码中,c
将会被赋值为-1,因为b的二进制码为01111111 11111111 11111111 11111111
,而转换后为11111111 11111111
,作为补码计算后结果为-1.
不兼容数据类型转换(Non-compatible Types Conversion)
什么是不兼容数据类型?
不兼容类型即本身在计算机中存储的方式有很大不同的类型,例如字符和整型,字符是存储的Unicode编码,而整型则存储的对应二进制,这类数据在进行转换的时候可能会出现不可控情况,所以被称为不兼容数据类型。
如何进行不兼容的类型的转换?
进行不同类型转换时所使用的方法通常会有很大的区别,下面是将字符串转换为浮点数的方法,实际编码中需要自行修改为对应的转换语句:
//double dPi = Convert.ToDouble(pi);
float dPi = float.Parse(pi);
Console.WriteLine(dPi);;
2.5 操作符
什么是操作符?
顾名思义,操作符就是对数据进行操作的符号,如对数据进行赋值、加减乘除运算等等。
操作符的类型有哪些?如何进行使用?
操作符类型有赋值运算符、算术运算符、比较运算符、逻辑运算符及位运算符,他们具体描述和用法见下:
赋值运算符(Assignment Operators)
运算符 | 举例 | 解释 |
---|---|---|
= | a = b | 基础赋值运算符,将b的值赋给a |
+= | a += b | 等同于 a = a + b |
-= | a -= b | 等同于 a = a - b |
*= | a *= b | 等同于 a = a * b |
/= | a /=b | 等同于 a = a / b |
算术运算符(Arithmetic Operators)
运算符 | 举例 | 解释 |
---|---|---|
+ | a + b | 加法运算符,将a 和b 进行做加法 |
- | a - b | 减法运算符,将a 和b 进行做减法 |
* | a * b | 乘法运算符,将a 和b 进行做乘法 |
/ | a / b | 除法运算符,将a 和b 进行做除法,最终会舍弃余数,如5 / 3 为1 |
% | a % b | 取余运算符,将a 和b 进行取余操作,只保留余数,如5 % 3 为2 |
++ | a++,++a | 递增运算符,等同于a = a + 1 |
– | a–,–a | 递减运算符,等同于a = a - 1 |
前置递增/递减和后置递增/递减:
-
代码书写区别:前置递增/递减和后置递增/递减在书写上的区别表现为前置运算符在被操作数之前,后置运算符在操作数之后。
-
单独书写运行结果:若果单独书写前置或后置运算符,其效果相同,均为递增或递减。
-
赋值中的前置与后置:在赋值运算中,前置运算会先进行递增/递减操作,再进行赋值,后置运算则会先进行赋值,在进行递增/递减操作,举例如下:
int a = 1; int b = a++;//后置递增,先进行赋值后递增,结果为b=1,a=2
int a = 1; int b = --a;//后置递减,先进行递减后赋值,结果为b=0,a=0
比较运算符(Comparison Operators)
运算符 | 举例 | 解释 |
---|---|---|
== | a == b | 比较a和b是否相等,若相等则值为True ,不相等则值为False |
!= | a != b | 比较a和b是否不相等,若不相等则值为True ,相等则值为False |
> | a > b | 比较a与b的大小,若a大于b则为True ,否则为False |
>= | a >= b | 比较a与b的大小,若a大于等于b则为True ,否则为False |
< | a < b | 比较a与b的大小,若a小于b则为True ,否则为False |
<= | a <= b | 比较a与b的大小,若a小于等于b则为True ,否则为False |
逻辑运算符(Logical Operators)
运算符 | 举例 | 解释 |
---|---|---|
&& | a && b | 逻辑与,若a和b同时为True 则结果为True ,否则为False |
|| | a || b | 逻辑或,若a和b有任何一个为True 则结果为True ,否则为False |
! | !a | 逻辑非,若a为True 则结果为False ,否则为True |
位运算符(Bitwise Operators)
位运算符是较为底层的运算操作符,直接针对二进制位进行的操作。
运算符 | 举例 | 解释 |
---|---|---|
& | a & b | a和b按位与运算,若对应二进制位全为1则结果中该位为1,如1010 & 0110 = 0010 |
| | a | b | a和b按位或运算,若对应二进制位有一个为1则结果中该位为1,如`1010 |
^ | a ^ b | a和b按位异或运算,若对应二进制位两位不相同则结果中该位为1,如1010 ^ 0110 = 1100 |
三目运算符(Ternary Operator)
三目运算符非常适用于对于一个结果为True
或False
时分别对应一种返回值的情况,他的基础语法为a ? b : c
,含义为当a
为True
则返回结果为b
,否则则为c
。下面是一个简单示例:
string res = 1 > 2 ? "1是大于2的" : "1小于2"; //最终res将被赋值为"1小于2"
运算优先级
什么是运算优先级?
当同一个式子中含有多个操作符的时候,存在运算优先级的概念,在运行时会先执行高优先级运算,后执行低优先级运算,在同级运算中,执行顺序为从左到右依次执行。例如:
1 & 2 - 3
计算时,减法优先度高于与运算,所以结果为1.1 + 2 * 3 - 4
计算时,乘法计算优先度高于加法,所以先进行乘运算,再依次进行其他运算,结果为3.
如何手动改变运算顺序?
想要更改计算顺序,可以手动对其添加括号(圆括号或方括号),程序将会优先执行括号中的内容,例如:
(1 & 2) - 3
计算时,将会优先执行与运算,后执行减法运算结果为-3.(1 + 2) * 3 - 4
计算时,将会先执行加法运算,结果变为5.
运算优先级参考链接:C# 运算符 | 菜鸟教程 (runoob.com)