一.调试和错误处理:
使用VS的调试功能,找到错误的原因并修改代码(调试);
正常模式(指的是不会影响程序的正常运行)下的调试:
1. 在VS中我们使用Console.Write(或WrightLine)方法向控制台输出变量的值,通过这个我们可以查看变量的值是否复符合我们的预期来调试错误。
2. 在Unity中我们使用Debug.Log(””)Debug.LogWarn(“”),向unity的Console窗口输出信息,帮助我们调试错误。
中断(Debug)模式下的调试:
Ps:中断模式是指我们可以暂停程序的执行,然后查看程序中的状态,也可以让程序继续执行。
断点:断点是源代码中自动进入中断模式的一个标记,当遇到断点的时候,程序会进入中断模式。
插入断点的方式:
1, 右击代码⾏,选择breakpoint(断点) -> insert breakpoint(插⼊断点);
2, 光标定位到代码⾏,选择菜单上的Debug(调试)->Toggle Breakpoint(切换断点) ;
3, 光标定位到代码⾏,按下F9键,在此按下F9是取消断点;
4, 在需要添加断点的⾏⾸位置,直接单击,再次单击取消断点。
窗口(Breakpoints):
我们可以通过 (调试-窗⼝-断点),打开断点窗⼝,这个窗⼝显⽰了当前项⽬中添加了的所有的断点,我们可以在这⾥定位断点的位置,也可以去删除断点。
中断模式下的窗口的左下角,有三个选项卡:
错误列表---程序运⾏中发⽣的所有错误的列表 ;
局部变量---当前运⾏环境中所有的局部变量的值 ;
监视---监视某个变量的值的变化 。
Ps:在上⾯的几个窗口中不但可以观察变量值的变化,还可以直接去修改变量中存储的值。
调用堆砌:
在调⽤堆栈窗⼝下我们可以观察到当前代码执⾏到哪⼀⾏了,并且可以看到这个代码的是 被什么语句调⽤的。
即时窗⼝:
即时窗⼝我们可以在这⾥输⼊⼀些命令,查看变量的值,修改变量的值,可以输⼊表达式查看结果。
处理异常语法:try,catch,finall。
Catch块中可以有0或者多个,finally可以有0或者1个,但是如果没有catch块,必须有finally块,没有finally块,必须有catch块,catch块和finally 块可以同时存在。
二.面向对象(OOP)编程:
类:
类实际上是创建对象的模板,每个对象都包含数据,并提供了处理和访问数据的⽅法。类定义了类的每个对象(称为实例)可以包含什么数据和功能。
类中的数据和函数称为类的成员:
数据成员:数据成员是包含类的数据--字段,常量和事件的成员。
函数成员:函数成员提供了操作类中数据的某些功能。(方法,属性,构造方法和终结器,运算符,索引器)
类的字段和方法:
字段的声明 访问修饰符 类型 字段名称;
⽅法的声明 访问修饰符 返回值类型 方法名称(参数){
//⽅法体
}
使用我们自定义的类声明的变量也叫做对象,这个过程也叫做实例化。
类的定义和声明:
例:
定义一个向量(Vector3)类,⾥⾯有x,y,z三个字段,有取得⻓度的⽅法,有设置属性(Set)的⽅法。(使⽤这个类声明一个变量(对象))
构造函数:
我们构造对象的时候,对象的初始化过程是⾃动完成的,但是在初始化对象的过程中有的时候需要做⼀些额外的⼯作,例如需要初始化对象存储的数据,构造函数就是⽤于初始化 数据的函数。
属性的定义:
属性的定义结构:
public int MyIntProp{
get{
// get code
} set{
//set code
}
}
1. 定义属性需要名字和类型 ;
2.属性包含两个块 get块和set块 ;
3.访问属性和访问字段⼀样,当取得属性的值的时候,就会调⽤属性中的get块,所以 get块,类型需要一个返回值就是属性的类型;当我们去给属性设置值的时候,就会调⽤ 属性中的set块,我们可以在set块中通过value访问到我们设置的值。
匿名类型:
我们创建变量(对象的时候),必须指定类型,其实我们也可以不去指定类型,这个就是 匿名类型,我们可以使⽤var声明一个匿名类型。
使⽤var声明的匿名类型,当初始化的时候,这个变量的类型就被确定下来,并且以后不可以修改。
程序的内存区域:堆 栈 静态存储区;
栈: 数据只能从栈的顶端插⼊和删除 把数据放⼊栈顶称为⼊栈(push) 从栈顶删除数据称为出栈(pop);
堆:堆是⼀块内存区域,与栈不同,堆⾥的内存能够以任意顺序存⼊和移除。
类型分为两种:值类型和引用类型;
值类型:整数,bool struct char 小数;只需要一段单独的内存,用于储存实际的数据(单独定义的时候放在栈中);
引用类型:s
tring数组 自定义的类,内置的类;需要两段内存,第一段储存实际的数据,它总是位于堆中,第二段是一个引用,指向数据在堆中的存放位置。
Ps:当我们使⽤引⽤类型赋值的时候,其实是赋值的引⽤类型的引⽤如果数组是⼀个值类型的数组,那么数组中直接存储值,如果是⼀个引⽤类型的数组(数组中存储的是引⽤类型),那么数组中存储的是引⽤(内存地址)。
面向对象 — 继承:
实现继承,接口继承,多重继承。
实现继承:
表⽰一个类型派⽣于⼀个基类型,它拥有该基类型的所有成员字段和函数。 在实现继承中,派⽣类型采用基类型的每个函数的实现代码,除⾮在派⽣类型的定义中指定重写某个函数的实现代码;在需要给现有的类型添加功能,或许多相关的类型共享⼀组重要的公共功能时,这种类型的继承⾮常有⽤。
接口继承:
表⽰一个类型只继承了函数的签名,没有继承任何实现代码。 在需要指定该类型具有某些可⽤的特性时,最好使⽤这种类型的继承。
多重继承:
即一个类派生自多个类,可以使用多重继承编写非常复杂,但很紧凑的代码,但是,使用多重实现继承的代码常常很难理解和调试,所以C#不支持多重实现继承,而C#允许类型派生自多个接口一一多重接口继承,这说明C#类可以派生自另一个类和任意多个接口,更准确的来说,System.Object是一个公共的基类,所以每个C#(除了Object以外)都有一个基类,还可以有任意多个基接口。
实现继承:
如果要声明派⽣⾃另⼀个类的⼀个类,就可以使⽤下⾯的语法:
class MyDerivedClass : MyBaseclass
{ // functions and data members here
}
如果类(或结构)也派⽣⾃接⼝,则⽤逗号分隔列表中的基类和接⼝:
public class MyDerivedClass: MyBaseClass , IInterface1 , IInterface2
{
// etc.
}
This和base关键字:
This(base)的作用:
1、IDE给提⽰
2、区分局部变量和字段
虚方法:把一个基类函数声明为virtual,就可以在任何派生类中重写该函数:
class MyBaseClass{
public virtual string VirtualMethod(){
return "Method is called in base class";
}
}
在派生类中重写另外一个函数时,要使用override关键字显示声明:
Class MyDerivedClass:MyBaseClass{
public override string VirtualMethod(){
return "Method is called in derivedclass.";
}
}
Ps:我们只要在子类里面重写虚函数了之后,不管在哪调用都是调用重写之后的方法。
隐藏方法:
如果签名相同的⽅法在基类和派⽣类中都进⾏了声明,但是该⽅法没有分别声明为virtual和override,派⽣类就会隐藏基类⽅法,(要使⽤new关键字进⾏声明) 基类。
class MyBaseClass{
public int MyMethod(){
}
}
派生类:
class MyDerivedClass :MyBaseClass{
public new void MyMethod() {
}
}
抽象类:
C#允许把类和函数声明abstract。 抽象类不能实例化,抽象类可以包含普通函数和抽象函数;抽象函数就是只有函数定义没有函数体;抽象函数本⾝也是虚拟的Virtual(只 有函数定义,没有函数体实现)。
Ps:类是⼀个模板,那么抽象类就是⼀个不完整的模板,我们不能使⽤不完整的模板去构造对象。
abstract class Building{
public abstract decimal CalculateHeatingCost();
}
密封类和密封方法:
C#允许把类和⽅法声明为 sealed;对于类,这表⽰不能继承该类,对于⽅法表⽰不能重写该⽅法
sealed FinalClass
{
// etc
}
Ps:为了防止重写某些类导致代码混乱和一些商业原因所以要运用密封类和密封方法。
修饰符:
修饰符:⽤来类型或者成员的关键字,修饰符可以指定⽅法的可⻅性。
public::同⼀程序集(DLL或EXE)中的任何其他代码或引⽤该程序集的其他程序集都可以访问该类型或成员。
private::只有同⼀类或结构中的代码可以访问该类型或成员。
internal::同⼀程序集中的任何代码都可以访问该类型或成员,但的代码不可以。 protected inter
nal: 在⼀程序集中,protected internal体现的是internal的性质,在其他程序集中,protected internal体现的是protected的性质。
类的修饰符:
Public class...(可以再别的项目下访问)
Class...
其他修饰符:
New:隐藏继承的成员;
Abstract:使⽤abstract修饰的类为抽象类,抽象类只能是其他类的基类,不能与sealed,static⼀起使⽤。 abstract可以修饰抽象类中的⽅法或属性,此时,⽅法或属性不能包含实现,且访问级别不能为私有。
Ps:抽象类不能被实例化。
Sealed:使⽤sealed修饰的类为密封类,密封类⽆法被继承,不能和abstract、static⼀起使⽤。当sealed⽤于⽅法或属性时,必须始终与override⼀起使⽤;
Static:使⽤static修饰的类为静态类,静态类所有成员都必须是静态的,不能与abstract、sealed ⼀起使⽤。static可以修饰⽅法、字段、属性或事件,始终通过类名⽽不是实例名称访问静态成员,静态字段只有一个副本。
Ps:静态类不能被实例化。
Const:使⽤const关键字来声明某个常量字段或常量局部变量,必须在声明常量时赋初值。不能与static⼀起使⽤,常量默认是static的,常量字段只有一个副本。
Readonly:使⽤readonly关键字来声明只读字段。 只读字段可以在声明或构造函数中初始化,每个类或结构的实例都有一个独⽴的副本。 可以与static⼀起使⽤,声明静态只读字段。 静态只读字段可以在声明或静态构造函数中初始化,静态常量字段只有一个副本。
Virtual:virtual关键字⽤于修饰⽅法、属性、索引器或事件声明,并使它们可以在派⽣类中被重写。默认情况下,⽅法是⾮虚拟的。不能重写⾮虚⽅法。
Ps:virtual修饰符不能与static、abstract、private或override修饰符⼀起使⽤。
Override:要扩展或修改继承的⽅法、属性、索引器或事件的抽象实现或虚实现,必须使⽤override修饰符。
Ps:重写的成员必须是virtual、abstract或override的。
泛型:
泛型类定义:
定义一个泛型类就是指的是,定义一个类,这个类中某些字段的类型是不确定的,这些类型可以在类构造的时候确定下来。
泛型方法:
定义泛型⽅法就是定义一个⽅法,这个⽅法的参数的类型可以是不确定的,当调⽤这个⽅ 法的时候再去确定⽅法的参数的类型。
实现任意类型组拼成字符串的方法:
public static T GetSum<T>(T a,T b){
return a+""+b;
}
GetSum<int>(23,12);
GetSum<double>(23.2,12);
使⽤泛型和索引器来实现⼀个我们⾃⼰的集合类MyList
有以下方法和属性:
1.Capacity获取容量⼤⼩;
2.Add()⽅法添加元素 ;
3.Insert()⽅法插⼊元素 ;
4.[index]访问元素(索引器) ;
5.Count属性访问元素个数 ;
6.RemoveAt()⽅法移除指定位置的元素;
7.IndexOf()⽅法取得⼀个元素所在列表中的索引位置 LastIndexOf()上⾯的⽅法是从前往后搜索,这个是从后往前搜索,搜索到满⾜条件的就停⽌;
Ps:上⾯的两个⽅法,如果没有找到指定元素就返回-1;
8.Sort()对列表中是元素进⾏从⼩到⼤排序 索引器:通过[index]这种形式去访问数据,就是索引器。