continue和break
这一块本来应该在循环那里讲的,现在才补上确实是我的疏忽。
countinue表示跳过当前循环,直接进入下一次循环,当遇到continue后,当前循环后面的代码都不会执行,直接进入下一趟循环,如果当前是最后一趟循环,则直接跳出循环。
break表示跳出循环,当遇到break后,当前循环不再执行,直接跳出,执行下面的代码。
都只能在循环体内使用,除了break在switch语句中还有跳出当前选择分支的作用外。
常量
正如同变量是可变的量,常量就是不可变的量。你可以认为它是只读的变量。声明如下:
const 类型 常量名 = 值;
常量名我们一般用全大写,以标识这是常量。像是应用标题,圆周率这些不需要在运行中变动的就可以用常量存储:
const string TITLE = "AppTitle";
const double PI = 3.14;
枚举类型
假如现在有星期日到星期六7个值,要求你表示,你可能会使用字符串数组:
string[] week = new string[] {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};
但是,这些值都是字符串类型的,可能会和其他字符串混淆。我们是否能够创建一个专属于星期的,不会和其他内容混淆的类型呢?
using System;
namespace Csharp
{
class Program
{
enum 星期
{
星期日, 星期一, 星期二, 星期三, 星期四, 星期五, 星期六
}
static void Main(string[] args)
{
}
}
}
我们使用enum关键字创建了一个名为星期的枚举类型,其中有7个值,分别对应一星期里的7天。
我们可以通过 枚举类型名.值 来调用其中的值。
using System;
namespace Csharp
{
class Program
{
enum 星期
{
星期日, 星期一, 星期二, 星期三, 星期四, 星期五, 星期六
}
static void Main(string[] args)
{
Console.WriteLine(星期.星期一);
}
}
}
输出为星期一。
那么,这到底有什么用呢?来看下面这段代码:
using System;
namespace Csharp
{
class Program
{
enum 星期
{
星期日, 星期一, 星期二, 星期三, 星期四, 星期五, 星期六
}
static void Main(string[] args)
{
星期 a;
int user_input = Convert.ToInt32(Console.ReadLine());
a = (星期)user_input;
Console.WriteLine(a);
}
}
}
输入0,输出星期日;输入6,输出星期六。可以看出,int类型是可以被显示转换为枚举类型的,这是为什么呢?
枚举类型实际上也给每个值设定了一个下标,从左到右分别为0,1,2,3,4,5,6......因此,星期日就是0,星期一就是1,以此类推,使得枚举类型和int类型可以互相转换。
这个下标是可以更改的,如下面代码:
enum FoodType
{
清新口味凝胶, 能量凝胶, 可乐, 精致的粽子 = 666, 信号棒, 罐头, 香喷喷炒面, 昂星干脆面, 钻石鱼子酱
}
其中,前三个值的下标分别为0、1、2,而第三个下标的值被改为了666,而第四个下标的值会在前一个上+1,所以信号棒的下标为667,罐头下标为668,钻石鱼子酱下标就是671。
不仅如此,枚举类型还承担着作为标志的作用。如下面这段代码:
using System;
namespace Csharp
{
class Program
{
static void Main(string[] args)
{
int runningState = 0; // 0表示运行中, 1表示立即结束运行, 2表示输出并结束运行
while (true)
{
if (runningState == 0)
{
continue;
}
else if (runningState == 1)
{
break;
}
else if (runningState == 2)
{
Console.WriteLine("运行结束");
break;
}
}
}
}
}
通过注释,我们可以知道0、1、2代表什么,但是当代码一长,注释就会被遗忘,到时候没人知道0、1、2分别代表什么运行状态。这时我们就可以用枚举类型代替:
using System;
namespace Csharp
{
class Program
{
enum RunningState
{
运行中, 立即结束, 输出并结束
}
static void Main(string[] args)
{
RunningState runningState = RunningState.运行中;
while (true)
{
if (runningState == RunningState.运行中)
{
continue;
}
else if (runningState == RunningState.立即结束)
{
break;
}
else if (runningState == RunningState.输出并结束)
{
Console.WriteLine("运行结束");
break;
}
}
}
}
}
现在,我们用直观的文字代替了意义不明的数字,让标识的管理更易于理解。
结构体
结构体主要被用于存储数据,并且可以有自己的成员变量和方法
定义
struct 结构体名
{
// 成员变量定义
作用域 类型 变量名;
......
// 方法定义
作用域 返回值类型 方法名(参数1, 参数2, 参数...)
{
代码块...
}
}
成员变量定义和变量定义一致,方法定义和函数定义一致。所以你可以这么看:成员变量就是属于结构体的变量,方法就是属于结构体的函数。
接下来我们创建一个名为Student的结构体,用于存储学生信息,并带有格式化输出学生信息的功能:
using System;
namespace Csharp
{
class Program
{
struct Student
{
public int age;
public string name;
public int id;
public void PrintInfo()
{
Console.WriteLine("学生"+name+age+"岁,编号"+id);
}
}
static void Main(string[] args)
{
Student Lihua;
Lihua.age = 16;
Lihua.name = "Lihua";
Lihua.id = 203960200;
Lihua.PrintInfo();
Student[] students = new Student[10];
students[0].name = "Jane";
}
}
}
为了方便,请把作用域全写为public,至于为什么,马上就会讲。
首先,我们声明了3个成员变量,分别是age(年龄)、name(名称)、id(编号),还有一个方法,调用后会格式化输出学生的信息。
然后,我们在Main函数内声明了一个Student类型的结构体Lihua,并通过 结构体对象名.成员变量 = 值 的方式为Lihua的成员变量赋值,最后通过Lihua.PrintInfo()格式化输出了Lihua的学生信息。
这段代码下面还有个例子,是Student数组,你可以通过数组索引到结构体对象,并修改其成员变量。
上面代码中,Student为结构体类型,Lihua为Student类型构造出的对象,而成员变量和方法都是面向对象而言的,只针对Lihua这个对象本身。
作用域
前面说为了方便,需要把作用域全写为public,这是为什么呢?作用域又是什么?
首先,一个变量定义出来不是哪个地方都能用的。
for循环的for(int i = 0; i < n; i++)这里的变量i就只能在for循环内访问,for循环外是访问不到的,会提示没有i这个变量。
一个函数内的形式参数也只有函数内能使用,函数外无法访问到。
同样的,结构体内的成员变量也只能在结构体内访问,外界正常来说是访问不到的。
这样的,只能在声明值的作用域内使用的作用域,就是private(私有的)。结构体成员变量的作用域如果不写,就默认为private。
如果我们想让这个变量在其他地方也能访问得到,只需要在填写作用域的位置写上public(公共的),这个变量就能被外界访问到了。这也就是为什么我刚才说要写public,如果不写,就不能在Main函数内访问Lihua的成员变量了。
引用类型与值类型
在讲委托之前,先搞清楚两个概念——引用类型和值类型。
首先,int、char、double、结构体都是值类型,顾名思义,这些变量内保存的都是实实在在的值,int存的就是数字,char存的就是字符,double存的就是浮点数,结构体存的就是成员变量。
但是引用类型不同,他存的是值的内存地址。什么意思呢?
首先,变量存的值会在内存中开辟一块区域供存储,当你调用变量时,本质是调用了这块区域,这片区域的门牌号就叫内存地址。
比如,a原本为10,存在内存地址A(存有10)内,现在a被重新赋值为11,则a会把内存地址A的10用11覆盖,这就是值类型的逻辑。
但是引用类型不同。例如,我现在在内存地址A存了10,我修改值为11后,他会指向新的内存地址B(存有11),而不是直接覆盖。
string是我们目前接触的唯二引用类型,我们如何确认这一点?可以使用object.ReferenceEquals()函数判断两个对象是否指向同一内存地址。
using System;
namespace Csharp
{
class Program
{
static void Main(string[] args)
{
int a = 10;
int b = a;
Console.WriteLine(object.ReferenceEquals(a, b));
string c = "我是字符串";
string d = c;
Console.WriteLine(object.ReferenceEquals(c, d));
}
}
}
运行结果如下:
false
true
可以看出,int传递的是值本身而非地址,而string传递的是地址而非值本身,证明了string确实是引用类型。
委托
委托类型属于引用类型,为了方便理解,我在前面讲述了引用类型和值类型的区别。
你可以认为委托类型存储的就是某个函数的内存地址,所以使用委托类型时就是在使用他所指向的函数。
声明委托类型如下:
delegate 返回值类型 委托名(参数1, 参数2, 参数…);
声明委托对象如下:
委托名 对象名;
你可以将任意一个返回值类型和参数(包括参数数量和参数类型)与委托完全相同的函数赋值给委托对象。
看下面这个例子:
using System;
namespace Csharp
{
class 委托
{
static double Average(double n1, double n2)
{
return (n1 + n2) / 2;
}
static double Sum(double n1, double n2)
{
return n1 + n2;
}
static void PrintPoint(PointDelegate dlg, double n1, double n2)
{
if (dlg != null)
{
Console.WriteLine("结果为{0}", dlg(n1, n2));
}
}
delegate double PointDelegate(double n1, double n2);
static void Main(string[] args)
{
PointDelegate point_func;
Console.Write("请输入两个数字:");
string[] _ = Console.ReadLine().Split(" ");
double a = Convert.ToInt32(_[0]);
double b = Convert.ToInt32(_[1]);
Console.Write("请输入求平均数[0]或求和[1]:");
int choice = Convert.ToInt32(Console.ReadLine());
if (choice == 0)
{
point_func = Average;
}
else {
point_func = Sum;
}
PrintPoint(point_func, a, b);
}
}
}
我们定义了两个函数,一个是求平均值,一个是求和,会根据用户输入不同给委托对象point_func赋值上不同的函数,然后通过PrintPoint函数输出结果。
你也可以认为委托就是给函数起的别名,毕竟内存地址相同,实质也就是相同的。而我上面的例子则是另一种用法,通过给委托赋值不同函数来让同一委托在不同情况下有不同的运行结果。
OK了,下一篇正式进入面向对象!

Comments NOTHING