C#
一、基础数据类型、变量、常量
1.1 C#开发语言特点
面向对象、简单的语言
C#语言继承C++的强大功能,同事去掉了复杂特性。
基于.Net框架
C#读音 C Sharp
1.2 C#中的注释
单行注释://
多行注释:/* */
1.3 基本数据类型
数据的量级
1024字节(byte)=1 KB
1024 KB = 1 MB
1024 MB = 1 GB
1024 GB = 1 TB
1024 TB = 1 PB
关键字 | 说明 | 字节大小 |
---|---|---|
bool | 逻辑值 | 1 |
sbyte | 有符号8位整数(-128-127) | 1 |
byte | 无符号8位整数(0-255) | 1 |
short | 有符号16位整数 | 2 |
ushort | 无符号16位整数 | 2 |
int | 有符号32位整数 | 4 |
uint | 无符号说位整数 | 4 |
long | 有符号64位整数 | 8 |
ulong | 无符号64位整数 | 8 |
char | 16位字符类型 | 2 |
float | 32位单精度浮点型 | 4 |
double | 64位双精度浮点型 | 8 |
decimal | 128位高精度浮点型 | 16 |
short—— int16
int —— int32
float——Single
double——Double
1.4 常量、变量
1、变量:在程序运行期间,可以改变
变量的声明:变量名 = 初值
int a = 10
不赋初值时,当前变量的值是默认值
2、常量:在程序运行期间,不能被改编
变量的声明:变量名 = 初值
const float money = 100.35f
常量必须要赋初值
3、浮点型声明时注意:
float money=10.35 f;(float要加f)
double damage=1.5 d; (double要加d)
decimal number = 1.3 m; (decimal要加m)
浮点类型的数字如果是整数,可以不加 f/d/m
4、字符类型声明注意:
字符型:char 必须加单引号。
5、变量命名的规则:
①只能由字母、数字、下划线(_) 、@ 组成,并且不能以数字开头,@要不不用,用时只能用在开头。
②不能与系统关键词同名
③不能使用重复的变量名
③中文变量名语法上可以,但极为不推荐。
6、变量命名的规范:
①全是英文单词,不要用拼音
②驼峰命名的方法:
大驼峰(每个单词的首字母大写,其余小写)
例子:MyHeroDamage、HeroAttack
小驼峰(第一个单词的首字母不大写,后面每个单词的首字母大写,其余小写):
例子:myHeroDamage、heroAttack
③见名知意(规范)
1.5运算符
-
赋值运算符:=
-
算术运算符:+ 、 - 、 * 、 /、 %(取余) 、 ++ 、 - -
+、 - 、 * 、 /、 %都是二元运算符
++、–是一元运算符
int ShowAge = age++;
Console.WriteLine(ShowAge);//ShowAge=18
//第一步:将age的值赋给Show Age
//第二部:age自增
//所以age++ 先赋值再运算
//Console.WriteLine(age);
int showAge = ++age;
//第一步:age自增
//第二部:将age的值赋给showAge
//所以age++ 先运算再赋值
Console.WriteLine(showAge);
- 复合运算符
- a+=b--------->a=a+b
- a-=b---------->a=a-b
- a**=b--------->a=a*b
- a/=b--------->a=a/b
- a&=b--------->a=a&b
1.6表达式
有常量、变量于运算符组成
例:3+5;
a+=b;
1.7语句
语句是程序执行的最小单位,以分号结尾
1.8基本输入输出语句
- 输出函数:
如果有using System 则 直接 Console.WriteLine()
若没有,则 System.Console.Write()
快捷方式:Console.WriteLine()
;//按cw再按两下tab键就出来了
Console.WriteLine()
:输出内容并换行
Console.Write()
: 输出内容不换行
-
输入函数
-
Console.Read()
; 从屏幕读取一个字符,并返回该字符所对应的整型 -
Console.ReadLine()
:从屏幕读取一串字符,并返回该字符-
字符串是一个数据类型
-
关键词string
-
用双引号
-
字符串相加可以得到两个字符串组合起来的字符串
-
-
1.9类型转换
- 隐式转换
- 将占用字节小的、取值范围小的、精度小的,转换为占用字节打的、取值范围大的、精度高
- 不需要任何修饰符,会自动转换
//整型
// 1 2 4 8
//sbyte short int long
sbyte englishScore = 100;
//sbyte -->int
int myScore = englishScore;//隐式转换,从小到大
//int --> long
long classScore = myScore;
//int -->float
float newScore = myScore;
//float -->double
double newClassScore = newScore;
-
显示转换:需要强制转换运算符。由大变小需要用将执行转换,这样需要付出缺失精度的代价。
-
jiang占用字节大的、取值范围大的、精度高转换为占用字节小的、取值范围小的、精度小的
-
需要强制转换修饰符,会有精度的缺失,甚至数据的错误。
-
int 转换成 sbyte
//强制转换 int damage = 1000000; //int --->sbyte sbyte health = (sbyte)damage; Console.WriteLine(health); Console.WriteLine("------------"); float mathScore = 90.5f; //float---->int int mymathScore = (int)mathScore; //会把小数点后的内容全部舍去 Console.WriteLine(mymathScore);
- int和char之间的类型转换
int num = 10001; //int--->char a=97char letter = (char)num; Console.WriteLine(letter);
- int和bool类型的转换
- 不能进行转换
-
string与其他类型之间的转换
(1)system.Convert
Convert.ToBoolean();
Convert.ToInt32();
Convert.ToSingle();
Convert.ToDouble();
Convert.ToChar();
(2)数据类型.Parse();
int.Parse()
bool.Parse()
float.Parse()
char.Parse()
其他类型转换成字符串:其他类型的变量.ToString()
1.10关系运算符
作用:描述前后表达式之间的大小关系,关系运算符一定是一个bool类型。
关系运算符:> ,< , >= , <=
还有==(等于) !=(不等于)
1.11逻辑运算符
作用:描述前后表达式之间的逻辑关系,关系运算符的结果一定是一个bool类型。
逻辑运算符是bool与bool之间的运算
- & : 与运算
- true&true : true
- true&false : false
- false&false : false
- 总结:一假则假
- true&true : true
- | : 或运算
- true | true : true
- true | false : true
- false | false : false
- 总结:一真则真
- ! 非
- ! true : false
- ! false : true
- && : 短路与运算
- 普通的&运算,无论第一个条件是真是假,都会继续判断第二个条件。
- 短路与运算&&,如果判断第一个条件已经是假,则不会继续判断第二个条件。
- ||:短路或运算
- 普通的|运算,无论第一个条件是真是假,都会继续判断第二个条件。
- 短路或运算||,如果判断第一个条件已经是真,则不会继续判断第二个条件。
- 短路&&、||
- 优点:第一个条件已经得知整个逻辑运算的结果,就不会判断第二个条件了
- 节约了运算量
- 缺点:如果判断中带有运算量,如果不进行第二个条件的判断,那第二个条件中的运算也不能执行。
- 优点:第一个条件已经得知整个逻辑运算的结果,就不会判断第二个条件了
1.12作业笔记
1、两个整型数字进行数学运算,结果还是一个整型数字。
如果想得到浮点型的计算结果,前面的数字只要有一个是浮点型。
2、补充一个新的注释号: #region 结尾 #endregion
快捷键:输入 #re后,按两下tab键
3、补充知识点:小括号这个运算符的优先级最高
4、保留两位小数
例子:float pi = 3.1415926f;
Console.WriteLine(pi.ToString("0.00"));
- ToString(“0.00”)
- Math.Round(数字,2)
二、分支结构
2.1三大结构
(1)顺序结构:程序的入口都是Main函数,代码从上往下,从左往右,依次执行;
(2)分支结构:当我们的程序执行到某个位置的时候,进行条件判断,根据判断的结果来执行不同的操作;
(3)循环结构:在满足某个条件的时候反复执行一个语句序列(循环)
其中if语句属于分支结构的语句
2.2 if 语句
(1)if语句的第一种表达形式:
if (条件表达式)
{
语句a;
语句b;
}
当条件表达式为真,执行大括号中的所有语句,否则,跳过打括号中的所有语句,继续执行大括号后面的语句。
(2)if 语句的第二种形式
if (条件表达式)
{
语句1;
}
else
{
语句2;
}
当条件表达式为真,执行if大括号中的所有的语句(语句1),否则,执行else大括号中的所有语句(语句2)。
(3)if语句的第三种形式
if(条件表达式1)
{
语句1;
}
else if(条件表达式2)
{
语句2;
}
else
{
语句3;
}
2.2.1条件运算符
归类为三目运算符
语法描述:关系运算/逻辑运算 ?结果为a:结果为b
结果:如果前面运算结果为true,则结果为a,否则结果为b
2.3 switch语句
Switch(表达式)
{
case 常量表达式1:语句序列1;break;
case 常量表达式2:语句序列2;break;
.
.
case 常量表达式n:语句序列n;break;
default:默认语句序列
}
如果 case冒号后面没有任何语句,就可以不加break。
Switch()括号中是可以允许添加浮点型变量的,但不推荐
-
浮点型是有误差的
-
浮点型一般不做等于的判断
-
企业面试题:有一个浮点数,判断该浮点数是不是等于5
2.4 循环结构
循环结构的特点:循环条件,循环操作
2.4.1 while 循环
while(条件表达式)
{
//循环内容
}
条件表达式一旦为真,执行循环体,一旦条件表达式为假,循环停止。
-
break
- 循环体中:跳出本层循环(通常与 if 连用)
-
continue:
- 在循环中的作用:结束本次循环
- continue后面的代码不再执行,进入下一次循环(通常与if 连用)。
2.4.2 do while 循环
do
{
//循环内容
}
while(条件表达式)
先执行循环体,再判断循环条件,直到条件不满足的时候,循环结束。
2.4.2 for循环
for(循环遍历初始化;循环条件;循环增量)
{
//循环体
}
循环条件为真,执行循环体
循环条件为假,跳出循环。
三 数组
作用:将相同数据类型存储在存储单元里组成的构造类型,数组的每个成员称为一个数组元素。
3.1 一维数组
1、定义:
数据类型[] 数组名;
在定义数组后,必须对其进行初始化才能使用
2、动态初始化
//数据类型[] 数组名 = new 数据类型[数组长度]
int[] intArray = new int[6];
//数据类型[] 数组名 = new 数据类型[数组长度]{元素1,元素2}
int[] intArray = new int[3]{1,2,3};
//注意:在这种情况下,不能将数组定义和静态初始化分开
或int[] intArray = new int[]{1,2,3}
- 动态初始化
- 数据类型[] 数组名 = new 数据类型[数组长度];
- 此时数组的每个元素都是为默认值
- int / float 的默认值为0
- bool 的默认值 false
- char的默认值 ‘\0’,表示空字符
- string的默认值 “”
- 此时数组的每个元素都是为默认值
- 数据类型[] 数组名 = new 数据类型[数组长度]{元素1,元素2。}
- 数据类型[] 数组名 = new 数据类型[]{元素1,元素2。。。。}
- 数据类型[] 数组名 = new 数据类型[数组长度];
- 静态初始化
3、数组元素的访问
元素访问:数组名+下标
例:array[3]
- 数组下标:数组元素在数组中的序号
- 数组下标从0开始计数
- 数组下标可以是常量也可以是变量
- 数组长度:arr.length 表示数组的长度,只读的
- 访问数组是,切记下标对应的数组元素是存在的
- 如果不存在,就会引发数组越界异常
4、引用类型
-
数据类型
-
值类型(存储在栈内存)
- 栈内存里存的是具体的值
-
引用类型(存储在堆内存)
-
栈内存里存的是地址(堆内存的地址)
-
目前学习过的引用类型
- string(特例)、数组
-
-
5、遍历数组
-
遍历数组:访问数组的每一个元素
int[] ads = { 80, 95, 98, 84 }; for(int i = 0; i < ads.Length; i++) { Console.WriteLine(i+":"+ads[i]); }
3.2 冒泡排序
思想:
- 当前数组元素与后面的数字元素进行对比,如果前大后小,则进行交换
- 每轮可以确定一个最大值在数组的末位,几轮之后即可完成排序
- 冒泡排序当然也可以从大到小,那样则前小后大进行交互
//核心思想:两两对比
//如果前大后小,则交换
int[] array = { 2, 1, 4, 5, 9, 7, 6, 3 };
//一共需要多少轮,数组长度-1
//0-8
// 两两对比
//0 1
//1 2
//2 3
//3 4
//4 5
//5 6
//6 7
//考虑内层
for (int i = 0; i < array.Length; i++)
{
//立个flag
bool hasExchange = false;
//-i是因为有几轮之后排好了几个数字,减去这几个
for (int j = 0; j < array.Length - 1-i; j++)
{
if (array[j] > array[j + 1])
{
//说明交换了
hasExchange = true;
//交换
int temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
}
}
if (!hasExchange)
{
//说明已经排好序了,后面的轮次就没有必要
break;
}
}
for (int i = 0; i < array.Length; i++)
{
Console.Write(array[i] +" ");
}
3.3二维数组
1、有两个下标的数组称为二维数组
2、二维数组本质上是以数组作为数组元素的数组,即“数组的数组”
3、动态初始化
类型[,]数组名= new 类型[常量表达式1,常量表达式2];
第一维的长度 第二维的长度
int[,] map=new int[3,5];
类型[,]数组名= new 类型[,]{数组值};
int[,] map=new int[,]{{1,0,1},{3,0,5}};
4、静态初始化
类型[,]数组名= {数组值};
int[,] map={{1,0,1},{3,0,5}};
5、二维数组的访问:数组名[下标1,下标2]
map[3,2];
//谨防下标越界
6、数组的长度
//总长度(二维数组的个数)
array.Length;
//第一维长度
array.GetLength(0);
//第二维长度
array.GetLength(1);
7、遍历二维数组
for (int i = 0; i < hero .GetLength(0); i++)
{
for (int j = 0; j < hero.GetLength(1); j++)
{
Console.Write(hero[i,j]+" ");
}
Console.WriteLine();
3.4迭代遍历foreach
foreach 语法
foreach(var item in number)
{
Console.WriteLine(item);
//循环体
}
迭代类型:必须和后面的迭代集合匹配,也可以使用模糊数据类型var
迭代集合:可以是数组、字符串、集合等
四 枚举和结构体
4.1枚举
定义枚举类型
枚举类型是自定义类型
enum 枚举名 {枚举值1,枚举值2...}
enum EquipType
{
Helmet,
BodyArmor,
Knapsack
}
枚举是一个值类型
4.2结构体
1、结构体是自定义类型
- 结构体类型的创建
struct Student
{
public string name;
public char sex;
public int age;
}
-
结构体类型变量声明及字段赋值
int num = 0; //定义一个学生变量 Student xiaom; //学生结构体 变量赋值 xiaom.name = "xiaominng"; xiaom.age = 18; xiaom.sex = 'M';
2、结构体不能有初值
3、结构体是值类型
4、结构体的构造函数
- 结构体默认的构造函数,开发者不能创建默认构造(即无参构造)
public Student()
{
}
-
结构体自定义的构造韩素,方便创建结构体变量时给字段赋值
public Student(string n,char s,int a) { name = n; sex = s; age = a; }
-
初始化结构体变量
Student xiaogang = new Student("xiaogang",'M',18);
构造函数是构造结构体时,调用的函数;
构造函数在结构体内创建
自定义的构造函数必须给所有的字段进行初始化赋值
4.3菱形题
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class test3
{
static void Main(string[] args)
{
#region 打印菱形
/*
n=4
上部分 s=n-i-1 *=2*i+1
* i=0 space=3 *=1
*** i=1 s=2 *=3
***** i=2 s=1 *=5
******* i=3 s=0 *=7
行数=[0-n]
s=i+1 *=(n-i-1)*2-1
***** i=0 s=1 *=5
*** i=1 s=2 *=3
* i=2 s=3 *=1
*/
Console.WriteLine("请输入数字:");
int n = int.Parse(Console.ReadLine());
//表示菱形上半部分的行数
for (int i = 0; i < n; i++)
{
//打印空格
for (int j = 0; j<n-i-1 ; j++)
{
Console.Write(" ");
}
//是否打印星星
bool printStar = true;
//打印*
for(int k = 0; k < 2 * i + 1; k++)
{
if (printStar)
{
Console.Write("*");
}
else
{
Console.Write(" ");
}
printStar = !printStar;
}
Console.WriteLine();
}
//下半部分
for (int i = 0; i < n-1; i++)
{
//打印空格
for (int j = 0; j < i+1; j++)
{
Console.Write(" ");
}
//是否打印星星
bool printStar = true;
//打印星星
for (int k = 0; k < (n - i - 1) * 2 - 1; k++)
{
if (printStar)
{
Console.Write("*");
}
else
{
Console.Write(" ");
}
//轮换
printStar = !printStar;
}
Console.WriteLine();
}
#endregion
}
}
}
五、访问修饰符
1、所有类型成员都具有可访问性级别,用来控制在其他代码位置能否访问到类型或成员,设置了成员的可访问限制,提高代码的安全性。
2、代码的位置层级划分:
- 程序集
- 程序集
- 命名空间
- 命名空间
- 命名空间
- 结构体
- 方法
- 方法
- 类
- 类
- 方法
- 方法
- 结构体
3、常用的访问修饰符
- public(公有的):同一程序集中的任何其他代码或引用该程序集的其他程序集都可以访问该类型或成员。
- private(私有的)︰只有同一类或结构中的代码可以访问该类型或成员。
- protected (受保护的)︰只有同一类或结构或者此类的派生类中的代码才可以访问的类型或成员。
- internal (内部的)︰同一程序集中的任何代码都可以访问该类型或成员,但其他程序集中的代码不可以。
- protected internal∶访问限制在当前程序集或从包含派生的类型的类别。
六、面向对象(OOP)
6.1 面向对象和面向过程
-
面向过程
- 面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。
- 重点关心解决问题的步骤。
- 优点
- 可以很清晰的看明白问题解决的步骤
- 代码的行数要少一点,性能消耗少一点
- 缺点
- 不易维护、不易拓展,不易复用
-
面向对象
- 面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。
- 重点关心解决问题过程中参与的对象有哪些,分别由哪些特性和行为。
- 优点
- 易维护、易复用、易扩展*,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵活、更加易于维护。
- 缺点
- 代码是分散的,行数会多些
- 性能消耗要高些
6.2 类和对象
-
类
-
类可以理解为类别,是具备某些共同特征的实体的集合,它是一种抽象的数据类型,它是对所具有相同特征实体的抽象。
-
类的创建
[访问修饰符] class 类名//大驼峰命名法 class Person { //在类内的字段是可以有初值的 public string nam=""; public int age; public char skinColor;//'\0' }
-
-
对象
-
对象的创建
//类名 对象名 Beautiful liuyifei=new BeautifulGirl();
-
类类型是一个引用类型
-
一个对象在创建后,需要进行实例化(初始化)才能使用
类名 对象名 = new 类名();
- 原理:对象在进行new操作后,才分配了内存
-
-
-
字段
-
描述一个类特征的变量
-
要使用小驼峰命名法命名
-
创建字段
class Person { public string name; public int age=18; } //默认访问修饰符为private,字段也可以设置初值
-
字段的访问
//对象名.字段名 Person xiaowu=new Person(); xiaowu.name="xiaowu"; xiaowu.name=18;
-
-
方法
- 定义
- 方法就是封装了一段有特定功能的代码段
- 方法就是用来描述一个类的行为
- 如果要完成一件大事
- 先定义一些方法,完成这个大事拆分原来的小事
- 最后再按照流程,在大事方法中调用这些小事的方法
- 如果要完成一件大事
-
方法创建
访问修饰符 返回值类型 方法名(参数列表) { 代码块 return 值 }
-
方法的调用
返回值类型 变量名=对象名.方法名(实参列表)
- 方法要用大驼峰命名
- 定义
-
帮助注释
-
帮助注释也是一种注释
-
谁可以添加帮助注释
- 类
- 方法
- 字段
- 属性
-
帮助注释的优点
- 在使用类、方法、字段、属性的时候,可以在提示框中显示帮助注释的内容。
-
-
this关键词
- 表示当前对象
- 如果没有重名冲突,可以不写省去
-
Random随机数类
-
第一步,先创建一个随机数对象
-
Random random = new Random();
-
第二步,调用随机数对象的Next方法
-
调用时要传入两个参数,即随机数字的取值范围
-
如传入的是4和8,则随机数字范围为4-7,不包含8(这个方法就是这么写的)
-
即取值范围为左闭右开,即[min,max]
-
方法返回的结果即随机到的数字,需要用整型变量去接收
-
int num=random.Next(0,array.Length);
-
-
-
属性,方法参数
-
引用类型变量的初值是null,表示空
-
声明了一个装备数组,并初始化
Equip[] heroEquip = new Equip[6];
- 由于装备对象还没有实例化(分配内存)所以初值都是null
- 如何给数组中的装备实例化呢?
-