一、调试和错误处理
1、错误(bug)
代码中总会出现不可避免的错误,比如变量名写错、未按规定定义函数等等,称为语义错误;书写代码时逻辑有瑕疵,称为逻辑错误。
2、调试
①Console.WriteLine()或者Console.Write()输出 ②Debug.Log()、Debug.LogError()、Debug.LogWarn()输出 ③中断(Debug)模式下的调试Console.ReadLine(),中断模式是指我们可以暂停程序的执行,然后查看程序中的状态,也可以让程序继续执行。 如何让程序中断:断点(双击打在数字行号前,遇到断点程序暂停,快捷键F9,或右键单击插入断点) 运行程序,会在断点出现暂停 逐语句和逐过程
3、错误(异常)处理
异常:在运行期间代码中产生的错误。 对可能发生错误的地方采取预防措施,并编写弹性代码来处理可能会发生的致命错误,异常处理又称为异常捕捉,常用try…catch…finally语句。
try//存放要捕捉异常的代码
{
//当这里面有一行错误,后续的不会继续执行,直接进入catch
}catch(
.....//出现该异常的时候怎么处理
}finally{
.....//不管出现异常没,都会执行
}
常见异常的类型: 用循环解决多次出错的问题,通break进行跳出循环
二、面向对象编程(OOP)
面向对象编程,又称模块化编程。为了让程序更加清晰,把程序中的功能进行模块化划分,每个模块提供特定的功能,而且每个模块都是孤立的,这种模块化变成提供了非常大的多样性,大大提高了重用代码的几率。
三、类
1、类
对象: 类创建的变量。 类: 实际上是创建对象的模版,每个对象都包含数据,并提供了处理和访问数据的方法。类定义了类的每个对象(实例)包含了什么数据和功能。类中的数据和函数称为类的成员。 创建新的类的步骤: 创建完成后还是在刚才的项目下(命名空间下),只是多了一个新的类。
2、类的成员
①数据成员:包含类的数据——字段、常量、和事件的成员。 ②函数成员:提供了操作类中数据的某些功能(方法、属性、构造方法和终结器(析构方法)、运算符和索引器)
class Customer
{
//定义数据成员(成员变量)
public String name;
public String address;
public int age;
public String creatTime;
//定义函数成员(成员方法)
public void Show()
{
Console.WriteLine("name:" + name);
Console.WriteLine("address:" + address);
Console.WriteLine("age:" + age);
Console.WriteLine("creatTime:" + creatTime);
}
}
3、用类创建对象
//利用类创建对象,c1就是对象名
Customer c1 = new Customer();
//可以分为以下两步
Customer c2;//声明对象
c2 = new Customer();//实例化对象,没有实例化就是空对象
//赋值
c1.name = "QDD";
c1.address = "四川";
c1.age = "18";
c1.creatTime = "2023";
//调用类中的方法
c1.show();
四、构造函数
在构造对象的时候,对象的初始化工作过程是自动完成的,但是在初始化对象的过程中需要做一些额外的工作,例如需要初始化对象存储的数据,构造函数就是用于初始化数据的函数。 声明基本的构造函数的语法就是声明一个所在类同名的方法,但是该方法没有返回值(没有返回值所以不用声明类型)。
①无参构造:
②带参构造:
③成员变量与构造函数参数重名的情况
五、属性
在原本的类中,我们对私有成员变量设置和获取值需要get和set函数,会使代码变得复杂:
//定义数据成员(成员变量)
private String name;
private String address;
private int age;
private String creatTime;
public void SetAge(int age)
{
this.age = age;
}
public int GetAge()
{
return age;
}
//在另一个类中调用
Customer li = new Customer();
li.SetAge(18);
li.GetAge();
①属性:
//属性
private int age;
//属性一般与成员变量同名,只是将手写字母大写
public int Age
{
//属性中包含两个块,get块相当于get函数,set块相当于set函数,又称访问器。可以只有一个get或者只有一个set.
get
{
return age;
}
set//value参数
{
age = value;
}
}
//在另一个类中
Customer li = new Costomer();
li.Age = 18;
console.WriteLine(li.Age);
②自动实现的属性:
//在代码中没有age这个数据
//private int age;
//系统会自动创建数据成员
public int Age{get;set};
③匿名类型: 根据变量值确定它的值的类型。
var 变量名 = 变量值;
六、继承
1、继承
很多类中有相似的数据,比如在一个游戏中,有boss类、小怪类Enemy,这些类他们有很多相似的属性,但是也有不同的,这个时候可以使用继承来让这两个类继承自同一个类(基类或父类)。 ①新建两个类,一个子类,一个基类 ②将子类继承自基类 ③使用尝试
class BaseClass
{
public void Founction1()
{
Console.WriteLine("这是功能1");
}
public void Founction2()
{
Console.WriteLine("这是功能2");
}
}
class Program
{
static void Main(string[] args)
{
BaseClass bc = new BaseClass();
bc.Founction1();
bc.Founction2();
}
}
使用子类去调用,结果是与基类调用相同的:
class Program
{
static void Main(string[] args)
{
//BaseClass bc = new BaseClass();
//bc.Founction1();
//bc.Founction2();
DriveClass dc = new DriveClass();
dc.Founction1();
dc.Founction2();
}
}
④this和base关键字(区别子类和父类) this用于访问子类里面的变量和方法。 base用于引用访问父类的变量和方法。
2、重写方法
继承之后,子类的功能和父类的功能不太相同,就需要进行重写方法。有虚方法和隐藏方法两种形式。
(1)虚方法
①在父类中将需要重写的方法名前加上关键字“virtual”。
②在子类中在正在重写的方法前加上关键字“override”。 调用,可以看到是子类重写的move()方法
(2)隐藏方法
隐藏方法的父类方法中,不作改变,相当于直接重写。而对于子类的重写方法中需要加上关键字"new"。
七、类相关
1、抽象类
C#允许把类和函数声明为abstract。抽象类不能实例化,抽象类可以包含普通函数和抽象函数,抽象函数只有函数定义没有函数体,显然抽象函数本身也是虚拟的virtual。类是一个模版,抽象类就是一个不完整的模版。如:定义一个抽象的敌人类: 此时我们发现如果想继承该抽象类就会报错,解决办法为实现该抽象类中的抽象方法。
2、密封类和密封方法
C#允许把类和方法声明为sealed。密封类不能被继承,密封方法不能被重写。被声明为sealed必须是已经被重写的方法。
3、派生类的构造函数
(1)在子类中调用父类的默认构造函数(无参),会先调用父类的,然后是子类的。 运行结果: ②调用有参数的构造函数。 另:自动生成构造函数的步骤:定义一个变量——》(右键)快速操作和重构——》生成构造函数——》选择成员——》确定
八、接口
一般情况下,接口只能包含方法,属性,索引器和事件的声明。接口不能有构造函数,也不能有字段,也不允许运算符重载。 ①定义(用I打头,代表一个接口) 定义一个接口和定义一个抽象类在方法上完全相同,但不允许提供接口中任何成员的实现方式。接口定义中不允许声明成员的修饰符,接口成员都是公有的。
②实现接口要实现接口里面所有的方法 ③用接口声明对象
Interface fly;
fly = new Fly();
//这时fly就有了Fly的功能
fly.Fly();
fly.Flyer();
④接口的继承 当Interface2继承了Interface1,在实现Interface2的方法时,也要实现Interface1的所有方法。
九、集合类
我们定义很多类型一样的数据,以前一般用数组存放,但是数组大小确定,存放数据量有限。如果我们存放很多类型一样的数据,比如游戏得分,我们可以用集合类来进行管理,比如列表List.
1、列表
①创建:列表可以存储任何类型的数据,但是我们再创建时需要指定创建的列表存放什么类型。在list后面加上尖括号加上类型——泛型。
//在创建后面加上大括号,中间加上数据可以增添初始值
List
//增加
list.add(100);
//访问、修改——索引(和数组一样)
Console.WriteLine(list[3]);
//遍历,for循环\foreach循环
//设置列表容量
list.Capacity = 100;
//列表数据的个数list.Count;
//插入Insert:在第3个数前插入数字800
list.Insert(3,800);
//移除Remove:移除值为32的数,假如列表中有两个32只移除第一个
list.Remove(32);
//查询某个数在列表中的索引位置
list.IndexOf(32);
//从后往前进行查找
list.LastIndexOf(32);
//对列表进行排序(从小到大)
list.Sort();
十、泛型
通过参数化类型来实现在同一份代码上操作多种数据类型。利用“参数化类型”将类型抽象化,从而实现灵活的应用。 ①定义
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CollectionAbout
{
class Program
{
static void Main(string[] args)
{
ClassA a = new ClassA(15,20);
Console.WriteLine(a.GetSum());
}
}
class ClassA
{
private int a;
private int b;
public ClassA(int a,int b)
{
this.a = a;
this.b = b;
}
public int GetSum()
{
return a + b;
}
}
}
通过该代码我们发现,如果此时我们要相加两个double类型的数据,仅仅只需要更改数据类型和方法名称了,但是确实需要复制一整段代码,很繁琐。这个时候可以使用泛型。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CollectionAbout
{
class Program
{
static void Main(string[] args)
{
//此时的<>中必须指明类型
ClassA
Console.WriteLine(a.GetSum());
}
}
class ClassA
{
private T a;
private T b;
public ClassA(T a,T b)
{
this.a = a;
this.b = b;
}
public T GetSum()
{
dynamic num1 = a;
dynamic num2 = b;
dynamic result = num1 + num2;
return (T)result;
}
}
}
十一、其他
1、Tostring()方法
将一个数据转化为字符串
Program p = new Program();
Console.WriteLine(p.ToString());
2、Equals()方法
比较的是引用地址,如果要比较的是地址之间的数值就需要重写Euqals方法。
int a = 12;
int b = 34;
Console.WriteLine(a.Equals(b));
好文链接
发表评论