5.运算符
1.convert类型转换
两个类型的变量兼容,可以使用自动类型转换或者强制类型转换
两个类型的变量不兼容,比如 string与int或者string 与double,这个时候我们可以使用一个叫做Convert的转换工厂进行转换。toInt32、toDouble、toChar
注意:使用Convert进行类型转换,也需要满足一个条件:
面儿上必须要过的去。 (即字符串“"123abc"不能转换为数值类型)
int d = Convert.toInt32(s)(要转换的变量)✅
将double变为int:强制转换:用(int)即可
2.加加减减
++:分为前++和后++,不管是前++还是后++,最终的结果都是给这个变量加一。
区别表现表达式当中,如果是前++,则先给这个变量自身加一,然后带着这个加一后的值去参与运算。num=10+1,10+11
如果是后++,则先拿原值参与运算,运算完成后,再讲这个变量自身加一。10+10,num=10+1
––:同上
对于像加加或者减减这样只需要一个操作数就能完成的运算,我们称之为一元运算符(只需要一个变量a)。
+ — * / % 对于这些需要两个或以上变量才能完成运算的操作符,我们称之为二元运算符。
一元运算符的优先级要高于二元运算符。既有一元运算符,又有二元运算符,我们首先计算一元运算符。先算a++、++a
3.关系运算符 < 、<=、 >、 >=、 == 、!=
关系运算符是用来描述两个事物之间的关系。由关系运算符连接的表达式称之为关系表达式。
关系表达式的结果是bool类型。 bool类型的值只有两个 一个true 一个false
4.逻辑运算符。 由逻辑运算符连接的表达式叫做逻辑表达式
&& 逻辑与:符号两边放的都是bool类型
||逻辑或:
!逻辑非:
同时有“与”和“或”,先 “与&&”再“或||”
5.复合赋值运算符 += 、-=、 *+、 /=、 %=
用&&而不用&,因为&&判断前一个条件不符合直接就返回false了,而&会两个条件都算一次。
6.结构
顺序结构:程序从Main函数进入,从上到下一行一行的执行,不会落下任何一行。
分支结构: if(bool){要执行的代码;} 、if( ){ }-else{ }、if( ){ }-else if( ){ }-else{ }
选择结构:if else-if switch-case
循环结构:while do-while for foreach
(内容同C语言)
//有两种以上情况的用if else-if
//第一种情况:用户名和密码全部输入正确
if (name == "admin" && pwd == "888888") {
Console.WriteLine("登陆成功");
}
//第二种情况:密码错误
else if (name == "admin") {
Console.WriteLine("密码输入错误,程序退出");
}
//第三种情况:用户名错误
else if (pwd == "888888") {
Console.WriteLine("用户名错误,程序退出");
}
//第四种情况:用户名和密码全部错误
else {
Console.WriteLine("用户名和密码全部错误,程序退出");
}
7.流程控制
1.异常捕获
我们在程序中经常会出现各种各样的异常,在你的代码中应该经常性的使用try{ }-catch{ }来进行异常捕获。try和catch之间不能有其他的代码。
try
{
可能会出现异常的代码;
....
...
...
}
//try和catch之间不能有其他的代码
catch
{
出现异常后要执行的代码;
} 要注意变量的三部曲问题 有一个出错后边另一个步骤可能就运行不了 e.g 输入数值 但是可能会输入abc导致无法转化 此时就要在声明变量时赋初值为0
如果try中的代码没有出现异常,那么catch中的代码不会执行。
如果try中的代码出现了异常,那怕这行出现异常的代码后面还有一百行都不会执行了,
而是直接跳到catch中执行代码 (类似于if-else)
以下报错:number变量是在try中声明的,超出try大括号就访问不到了。因此console.writeline会报错。
变量的作用域:变量的作用域就是你能够使用到这个变量的范围(局部变量)。
变量的作用域一般从声明它的那个括号开始到那个括号所对应的结束的括号结束。在这个范围内,我们可以访问并使用变量。超出这个范围就访问不到了。处理方法:在括号外声明。
如果try报错,即不能成功转换数据类型(如输入50abc),那么执行catch+console.writeline(writeline仍会被执行,输出为0)。catch和console.writeline不矛盾
如果try不报错,即能成功转换数据类型,那么继续往下执行。
2.switch-case
是对定值的判断。如评级是A/B/C,工资明年到底是+100还是+200还是+300。
switch(level){case'A':} 相当于 if(level=A){}
if else-if 处理的是带范围的判断(if level>A)。
b=true
switch(level) //先计算变量或者表达式的值,再跟下面的case比较
{
case 'A':salary+=100 //'A'的类型必须和“level”一致
break;
case 'B':salary+=200;
break;
case 'C':salary+=300;
break;
..........
default:Consle.WriteLine('imput error'); //跟以上的case都不符合,则执行default
b=false;
break;
}
if(b) //如果跳到default中,b会变成false,则不执行该部分。否则,代表salary计算完毕,执行该部分
{Consle.WriteLine('calculated finished');
}
//输出输入的月份对应的天数
Console.WriteLine("请输入年份");
try {
int year = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("请输入月份");
int month = Convert.ToInt32(Console.ReadLine());
if (month >= 1 && month <= 12) {
int day = 0;
switch (month) {
case 1: //如果冒号后面的语句和下面一样,可以省略。一直到不一样为止
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
day = 31; //以上几个月都是31天
break;
case 2: //2月有闰年和平年的区别。闰年是29天,平年是28天。
if ((year % 400 == 0) || (year % 100 != 0 && year % 4 == 0)) {
day = 29;
} else {
day = 28;
}
break;
default:
day = 30;
break;
}//switch的括号
Console.WriteLine("{0}年{1}月有{2}天", year, month, day);
} //if的括号
else {
Console.WriteLine("输入的月份有错,请重新输入");
}
}//try的括号
catch {
Console.WriteLine("输入的年份有错,请重新输入"); //trycatch的好处是不会抛出异常。客户如果看到抛异常,会觉得软件不好用,所以哪怕是抛异常了,也要处理得像是没有抛异常一样
}
Console.ReadKey();
3.循环结构
(1)while(循环条件){循环执行;}:
while:特点:先判断,再执行,有可能一遍循环都不执行。( 同C )
(2)for循环
for(表达式1;表达式2;表达式3){执行代码;} 。表达式2不成立时跳出循环。
效果用while也能实现:
区分while循环:在已知循环次数的时候(见表达式2),用 for循环。不知道循环次数的时候,用while循环。
例题:
Write和WriteLine区别:
Conosole.Write("\t"); //输入后不换行
Console.WriteLine(); //什么都不写也会自动换行
例题:输入加法公式
4.break、continue、return
(1)break
可以跳出switch-case结构。
可以跳出当前while循环、不再进行下一轮循环。
break一般不单独的使用,而是跟着if判断一起使用,表示,当满足某些条件的时候,就不再循环了。
(2)continue
continue 和break一样也是跳出当前循环,但会进行条件判断,条件符合则继续下一轮循环
(3)return:有返回值则返回返回值,没有返回值的,跳出本main函数。
5.类型转换TryParse。转换不成功不会报错
区分:convert.Int32和int.Prase、double.Prase等 ,这两个如果转换不成功会报错
int number = 100;
bool b = int.TryParse("123abc",out number); //把数值转换为数字并赋值给number 这里的TryPrase是一个方法 如果转换成功则b为true number为转换后的值 如果不成功则b为false 并赋值number = 0
//不同于convert.Int32和int.Prase 这两个如果转换不成功会报错
Console.WriteLine(b);
Console.WriteLine(number);
若int.TryParse转换失败,则b为false,number=0
6.断点调试
调试方法:
1)F11逐语句调试(单步调试)。可以将变量拖进监视里监视,如果变成红色代表发生变化
2)F10逐过程调试
3)断点调试
7.三元表达式:能用if-else表示的,都可以考虑用三元表达式
表达式1?表达式2:表达式3;
表达式1一般为一个关系表达式。
如果表达式1的值为true,那么表达式2的值就是整个三元表达式的值。
如果表达式1的值为false,那么表达式3的值就是整个三元表达式的值。
注意:表达式2的结果类型必须跟表达式3的结果类型一致,并且也要跟整个三元表达式的结果类型一致。
8.创建随机数。没有对象,new一个,取名为r。让r产生一个1到10之间的随机数rNumber。
//1.创建一个能够产生随机数的对象。没有对象,new一个
Random r = new random();
//2.让产生随机数的这个对象调用方法来产生随机数
int rNumber = r.Next(1,10) //取左不取右
举例:这个人上辈子是干什么的?
8.复杂数据类型(常量、枚举、结构、数组)
1.常量const+
const int number = 10; 这就是定义了一个常量 常量是不可以改变的、不可以被重新赋值的。
e.g 超市哪一天打几折 这时候就可以用到常量了
2.枚举enum。枚举和之前的int、double是一样的、都是一种数据类型。起到了规范的作用 比如性别用男和女来命名,有多种词语,如男、male、爷们 。这时候就可以用枚举来规范,将某一个固定的称谓。
[public] enum 枚举名{ //public也可以省略 最好还是写出来
值1,
值2,
值3 //最后一个数据的后边逗号可以省略 表示是最后一个
}
//定义枚举时可以在命名空间下类上声明或者类下函数前声明 绝对不能在函数里声明。否则出了函数就访问不到了
public:访问修饰符。访问权限是最高的,在哪都可以访问到该变量、公开的。可以省略。
建议:将枚举声明到命名空间namespace的下面,类的外面,表示这个命名空间下,所有的类都可以使用这个枚举。
如例题。枚举相当于是重新定义了一个数据类型Gender:(对比string gender)
//函数里
{
Discount d1 = Discount.nine;
Season s1 = Season.夏;
}
namespace _04枚举和int以及string类型之间的转换(以下类型不用背,用的时候查询就可以)
{
public enum QQState
{
OnLine, //枚举内容是第一个内容默认对应的数字是0 后边递增.0,1,2,3,,,
OffLine,
Leave,
Busy,
QMe
}
class Program
{
static void Main(string[] args)
{
#1、region 将枚举类型强转成int类型。强转的枚举类型会从0开始、0,1,2,3,,,
//QQState state = QQState.OnLine;
枚举类型默认可以跟int类型互相转换 枚举类型跟int类型是兼容的
//int n = (int)state;
//Console.WriteLine(n); //强转后n=0
//Console.WriteLine((int)QQState.OffLine); //强转后OffLine=1
//Console.WriteLine((int)QQState.Leave); //强转后Leave=2
//Console.ReadKey();
#endregion
#2、region 将int类型强转为枚举类型:
//int n1 = 3; //8
//QQState state = (QQState)n1; //将n1强制转成QQState类型
//Console.WriteLine(state); //Busy //如果n1为8(比枚举内容大) 则打印出来还是8
//Console.ReadKey();
#endregion
#3、region 将枚举类型转换成字符串类型
//所有的类型都能够转换成string类型ToString,包括int、double、decimal、string等,当然也包括QQState类型
// int n1 = 10;
double n1 = 3.14;
// decimal n1 = 5000m;
// string s = n1.ToString();
// Console.WriteLine(s);
// Console.ReadKey();
//QQState state = QQState.OnLine;
//string s = state.ToString();
//Console.WriteLine(s);
//Console.ReadKey();
#endregion
#4、region 将字符串类型转换为枚举类型
//string s = "0";
将s转换成枚举类型:直接转换会失败,因为不兼容。必须要通过Parse()。
Convert.ToInt32() int.parse() int.TryParse() //转换的三种方法Convert、parse、TryParse。
Parse()方法的目的:将字符串转换成枚举类型Enum.Parse(typeof(QQState), s),换成QQState的类型
//QQState state = (QQState)Enum.Parse(typeof(QQState), s); //如果输入的字符串枚举里边没有则会报错 ,如s = "ABCDEFG"。
//Console.WriteLine(state); //OnLine
//Console.ReadKey();
#endregion
//5、例题:枚举练习
//提示用户选择一个在线状态,我们接受,并将用户的输入转换成枚举类型。
//再次打印到控制台中
Console.WriteLine("请选择您的qq在线状态 0--OnLine 1--OffLine 2--Leave 3--Busy 4--QMe");
string input = Console.ReadLine();
switch (input)
{
case "0": QQState s1 = (QQState)Enum.Parse(typeof(QQState), input); //将input变为QQState类型,即0变成QQState类型
Console.WriteLine("您选择的在线状态是{0}",s1);
break;
case "1": QQState s2 = (QQState)Enum.Parse(typeof(QQState), input);
Console.WriteLine("您选择的在线状态是{0}",s2);
break;
case "2": QQState s3 = (QQState)Enum.Parse(typeof(QQState), input);
Console.WriteLine("您选择的在线状态是{0}",s3);
break;
case "3": QQState s4 = (QQState)Enum.Parse(typeof(QQState), input);
Console.WriteLine("您选择的在线状态是{0}", s4);
break;
case "4": QQState s5 = (QQState)Enum.Parse(typeof(QQState), input);
Console.WriteLine("您选择的在线状态是{0}", s5);
break;
}
Console.ReadKey();
}
}
}
3.结构struct。一次性声明多个不同类型的变量。
语法:
[public] struct 结构名
{
public string _字段; //字段加public这也下边也可以用。字段前边要加下划线。
}
变量和字段的区别:变量在程序运行期间只能存储一个值,而字段可以存储多个值(一个name,可以存成张三、小兰)。;字段前边要加下划线
//结构和枚举的结合应用
namespace _02_结构练习
{
public enum Gender
{
男,
女
}
public struct Person //定义了一个Person变量
{
public string _name; //定义了一个name字段
public int _age;
public Gender _gender; //应用了上边的枚举类型
}
class Program
{
static void Main(string[] args) {
Person zsPerson; //声明一个Person变量,取名为zsPerson
zsPerson._name = "张三";
zsPerson._gender = Gender.男;
zsPerson._age = 18;
Person xlPerson;
xlPerson._name = "小兰";
xlPerson._gender = Gender.女;
xlPerson._age = 16;
Console.WriteLine("我叫{0}是{1}的今年{2}岁了",zsPerson._name,zsPerson._gender,zsPerson._age);
Console.WriteLine("我叫{0}是{1}的今年{2}岁了",xlPerson._name,xlPerson._gender,xlPerson._age);
Console.ReadKey();
}
}
}
4.数组:一次性声明多个相同类型的变量。区分结构:一次性声明多个不同类型的变量。
语法:
数组类型[] 数组名=new 数组类型[数组长度]; 最常用的数组int[ ]
int[] a = new int[10]; //定义了一个int类型长度为10的数组。声明方式一。
int[] a = {0,1,2,3,4,5,6}; // 确定了数组初值。声明方式二。
a[3] // 拿到数组的第三个元素
int[] a = new int[7]{0,1,2,3,4,5,6}; // 确定了数组初值。声明方式三。
int[] a = new int[]{0,1,2,3,4,5,6}; // 确定了数组初值。声明方式四。
索引不能超过下界 数组的长度一旦固定了,就不能再被改变了
int类型默认全为0 ,string默认全为null ,bool类型默认全为false
null和“ ”空不一样 ,null没有开辟空间而空有
比较数组中的最大值最小值最好就是随便把数组内的一个值赋值给最大最小值 ,不要赋值为0
//将一个数组升序
int[] nums = {1,4,5,68,4,11,6};
Array.Sort(nums); //按升序顺序排序
Array.Reverse(nums); //将数组反转 顺序无变化
都是直接改变了数组
到老牛就就停止循环,然后直接加上老马。这样就不用怕老马后面又跟了一个竖线|
对调顺序
9.方法/函数
1.定义
函数的语法:
[public] static 返回值类型 方法名([参数列表])
{
方法体;
}
// static:静态的
// 返回值类型:如果不需要写返回值,写void。一般默认void,有返回值了再改
// 如果没有参数,也不能省略括号
// 平时写的Console.WriteLine(); 也是一种调用方法 调用的是Console这个类的WriteLine这个方法
方法定义:写方法时在main函数外面写。[public] static 返回值类型 方法名()。
既要写函数体和函数的作用 ,方便使用
方法调用: 在Main()函数中调用。 类名.方法名([参数]);
如系统内置的类有方法Console.Writeline(max)
在某些情况下,类名是可以省略的,如果你写的方法跟Main()函数同在一个类中,这个时候,类名可以省略。(不可以省略的例子看上方代码块注释部分)
2.调用
以下会报错。因为a只在main函数中能访问到。
我们在Main()函数中,调用Test()函数。
如果被调用者Test()想要得到调用者Main()里面定义的值:有以下几个方法
1)、传递参数。
但是注意,在test函数中,a的值变为8,但是这个a的值并没有传递到函数外面。在函数外面,如main函数中,a仍然为3。怎么让a的值8传出去呢?答案:test()中通过返回值返回出去
2)、使用静态字段来模拟全局变量。c#中没有全局变量这个东西,因此只能用静态字段来实现全局变量的功能。
// public static int _number = 10;定义在类下和其他函数同级,那么只要是类下的函数都能够调用该变量。
不管是实参还是形参,都是在内存中开辟了空间的。
例题:
3.out、ref、params高级参数
1) out参数。返回多个不同类型的值,如返回值中有int、string、bool。。。相同类型的值也可以
如果你在一个方法中,返回多个相同类型的值的时候,可以考虑返回一个数组。
但是,如果返回多个不同类型的时候,返回数组就不行了,那么这个时候,我们可以考虑使用out参数。
使用方法: 注意:方法GetMaxMinSumAve内必须对out的参数进行赋值
static void Main(string[] args) {
int[] number = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
GetMaxMinSumAve(number, out int max, out int min, out int sum, out int ave);//实参列表。
//本例中返回值全是int。但现实中返回值可以有很多种类型
Console.WriteLine("Max = {0},Min = {1},Sum = {2},Ave = {3}", max, min, sum, ave);
Console.ReadKey();
}
/// <summary>
/// 给定数组
/// 求最大最小值,总和,平均值
/// </summary>
/// <param name="nums">所求数组</param>
/// <param name="max">最大值</param>
/// <param name="min">最小值</param>
/// <param name="sum">总和</param>
/// <param name="ave">平均值</param>
public static void GetMaxMinSumAve(int[] nums, out int max, out int min, out int sum, out int ave) {// 形参列表。
//方法内必须要对out的参数进行赋值,因为值要传递给main函数。
//有形参来接收值,不需要再写return!
max = nums[0]; //先预设以下值。注意不用写成int max,因为上面形参列表已经声明了变量。
min = nums[1];
sum = nums[2];
ave = 0;
for (int i = 0; i < nums.Length; i++) {
if (nums[i] > max) {
max = nums[i];
}
if (nums[i] < min){
min = nums[i];
}
sum += nums[i];
}
ave = sum / nums.Length;
}
例题:形参列表是声明参数的,实参列表是给参数赋值的。该方法内部需要给num赋值,并另外return bool类型的值。
2) ref参数。能够将一个变量带入一个方法中进行改变,改变完成后,将改变后的值带出方法。
ref参数要求在方法外必须为其赋值,而方法内可以不赋值。(因为要把外面的值带到方法里边去 ,所以先在方法外赋值)
使用方法
static void Main(string[] args) {
int n1 = 10;
int n2 = 20;
Swap(ref n1, ref n2);
Console.WriteLine("n1={0},n2={1}",n1,n2);
Console.ReadKey();
}
public static void Swap(ref int n1,ref int n2) {
int temp = n1;
n1 = n2;
n2 = temp;
}
不用ref的写法:
例题:
3) params可变参数
将实参列表中(99,88,77) 跟形参列表中可变参数数组(int[ ])类型一致的元素(int)都当做数组的元素去处理。
但params可变参数必须是形参列表中的最后一个元素。
不用params时,只能传入数组
有了params后,实参可以传入int,在形参中会将其变为数组:
使用方法:
static void Main(string[] args) {
int sum = GetSum(1,2,3,4,5,6,7,8,9);
Console.WriteLine(sum);
Console.ReadKey();
}
public static int GetSum(params int[] s) { //每个实参都变成了数组中的元素 最后结果为45
int sum = 0;
for (int i = 0; i < s.Length; i++) {
sum += s[i];
}
return sum;
}
params可变参数必须是形参列表中的最后一个元素:
例题:任意长度数组:可以是123、可以是123456。因为一般数组的长度都是固定的,可以尝试用可变参数数组params
4.方法重载 (同c++):方法名字相同,但是参数不同
参数不同分为两种情况:
1.参数的个数相同, 则参数的类型不能相同。如图中的第一个M1和第二个方法M2
2.参数的类型相同, 则个数不能相同。如图中的第一个M1和第三个方法M3
以下四个方法本质上都是在相加,如果不用重载的情况下,要调用下面四个调用函数。用了重载,只需要写一个函数,再根据传进去的参数自动判断到底想要调用哪个函数。
不用重载:
函数重载与返回值类型没关系。因此以下两个方法由于参数的个数和类型都相同,不构成重载。
5.方法递归:自己调用自己
使用方法
{
static void Main(string[] args) {
int i = 0;
TellStory(i);
Console.ReadKey();
}
public static void TellStory(int i) {
Console.WriteLine("从前有座山,山里有座庙,庙里有个小和尚和老和尚,老和尚对小和尚讲了个故事:");
i++;
if (i > 10) {
return;
} //递归10次
TellStory(i); //此处自己调用自己。执行到这里之后又重头开始,代表进入下一层递归。
//如果递归完毕,要出去的话,会从该行出去!debug看此行执行了10次,是在出去。出去不是从return出去的!
Console.WriteLine("我是第{0}次", i);
}
10.飞行棋项目
1.设置游戏界面
//设置前景色(文字的颜色)
Console.ForegroundColor = ConsoleColor.Red;//这是一个枚举 所以这样来调用
//设置背景色
Console.BackgroundColor = ConsoleColor.Red;
2.输入姓名
//输入后应该清屏
Console.Clear();
3.启动项目
//按下任意键投骰子
Console.ReadKey(true); //true 输入的任意键不会被显示 false为显示
当用到大括号{}时 要在尾部注释这是哪个语句的 //while //else