这是Program类
using System;
using System.Collections.Generic;//需要引用
namespace 学习C_的中级编程
{
class Program
{
static void Main(string[] args)
{
//一、调试和错误处理
//1.语法错误
//2.逻辑错误
//3.VS中我们使用Console.Write(或者WriteLine)方法
//4.Unity中我们使用Debug.Log("") Debug.LogError("") Debug.LogWarn(""),向unity的Console窗口输出信息,帮助我们调试错误。
//二、添加断点、进行调试
//1.断点是什么?
//断点是源代码中自动进入中断模式的一个标记,当遇到断点的时候,程序会进入中断模式。
//2.如何插入断点?
//1,右击代码行,选择breakpoint(断点)->insert breakpoint(插入断点)
//2,光标定位到代码行,选择菜单上的Debug(调试)->Toggle Breakpoint(切换断点)
//3,光标定位到代码行,按下F9键,在此按下F9是取消断点
//4,在需要添加断点的行首位置,直接单击,再次单击取消断点
int num1 = 24;
int num2 = 30;
string num3 = "帝三";
int res = num1 + num2;
Console.WriteLine(res);
Console.WriteLine(num1);
Console.WriteLine(num2);
Console.WriteLine(num3);
//三、面向对象编程
//1.什么是面向对象编程?
//为了让编程更加清晰,把程序中的功能进行模块化划分,每个模块提供特定的功能,而且每个模块都是孤立的,这种模块化编程提供了非常大的多样性,大大增加了重用代码的机会
//简单来说,面向对象编程就是结构化编程,对程序中的变量结构划分,让编程更清晰。
//2.什么是对象?
//我们把类创建的变量叫做对象
//四、类
//1.类的定义?字段的声明?方法的声明?
//2.如何利用类创建对象?
//2_1.使用我们自定义的类声明的变量也叫做对象,这个过程也叫做实例化
//2_2.如果要使用一个类的话,要先引入它所在的命名空间,Customer位于当前的命名空间下,所以不需要引入,我们可以直接使用Customer
Customer tes1;//在这里我们使用Customer,声明了一个变量,这个变量叫做对象
tes1 = new Customer();//对对象初始化,需要使用new 加上类名
tes1.name = "小明";//我们自己定义的类声明的对象,需要先进行初始化,才能使用
tes1.Show();
Console.WriteLine(tes1.name);
//五、编程规范上面,习惯把所有的字段设置为private,只能在类的内部访问,不可以通过对象访问,那我们怎么进行访问呢?
//为字段提供set方法,来设置字段的值
//如果我们直接在方法内部访问同名的变量的时候,优先访问最近(形参)
//我们可以通过this.表示访问的是类的字段或方法
tes1.SetX(2.2f);
Console.WriteLine(tes1.Length());
//六、构造函数
//1.什么是构造函数?
//我们构造对象(变量)的时候,对象的初始化过程是自动完成的,但是在初始化对象的过程中有的时候需要做一些额外的工作,
//例如需要初始化对象存储的数据,构造函数就是用于初始化数据的函数。
//2.声明基本的构造函数的语法就是声明一个和所在类同名的方法,但是该方法没有返回类型!
//3.当我们使用new关键字创建类的时候,就会调用构造方法。
//4.我们一般会使用构造方法进行初始化数据的一些操作。构造函数可以进行重载,跟普通函数重载是一样的规则。
//5.注意:
//当我们不写,任何构造函数的时候,编译器会提供给我们一个默认的 无参的构造函数,
//但是如果我们定义了一个或者多个构造函数,编译器就不会再提供默认的构造函数
Vector3 v1 = new Vector3(1.2f,2.2f,3.2f);
//v1.SetX(1.2F);
//v1.SetY(2.2F);
//v1.SetZ(3.2F);
Console.WriteLine(v1.Length());
//七、属性的定义
//1.定义属性需要名字和类型,不需要型参
//2.属性包含两个块 get块和set块
//3.访问属性和访问字段一样,当取得属性的值的时候,就会调用属性中的get块,所以get块,类型需要一个返回值就是属性的类型。
//当我们去给属性设置值的时候,就会调用属性中的set块,我们可以在set块中通过value访问到我们设置的值。
//使用属性跟使用字段一样
v1.MyIntPropety = 600;//对属性设置值-输出的是set和get以及set中的value值
int temp = v1.MyIntPropety;//对属性取值
Console.WriteLine(temp);//输出的值是get里的返回值
//八、通过属性来访问字段
//1.我们习惯上把字段设置为私有的,这样外界不能修改字段的值,然后我们可以通过定义属性来设置和取得字段中的值
//2.设置属性的只读或者只写-就是只写set方法就是只写,get方法就是外界不能设置值了-只读
//3.自动实现的属性- private string Name { set;get; }//简写形式-编译器会自动给我们提供一个字段,来存储name
v1.X = 110;
float temp1 = v1.X;
Console.WriteLine(temp1);
v1.Age = -20;
int temp2 = v1.Age;
Console.WriteLine(temp2);
v1.Name = "简写形式";
string temp3 = v1.Name;
Console.WriteLine(temp3);
//九、匿名类型
//1.我们创建变量(对象的时候)必须指定类型,其实我们也可以不去指定类型,这个就是匿名类型,我们可以使用var声明一个匿名类型
//2.使用var声明的匿名类型,当初始化的时候,这个变量的类型就被确定下来,并且以后不可以修改
var i = 89;//这个变量的类型就被确定下来是int类型
//i = "如果再赋值一个字符串就不行了"
//十、了解堆和栈(对理解程序和写程序有帮助)
//1.我们把内存分为堆空间和栈空间
//栈空间比较小,但是读取速度快
//堆空间比较大,但是读取速度慢
//2.栈的特征
//2_1.数据只能从栈的顶端插入和删除-先入栈的后出比如1 2 3,那么3先出栈 2再出 1是最后出栈的
//2_2.把数据放入栈顶称为入栈(push)
//2_3.从栈顶删除数据称为出栈(pop)
//3.堆栈的特征
//3_1.堆是一块内存区域,与栈不同,堆里的内存能够以任意顺序存入和移除
//4.GC Garbage Collector垃圾回收器
//4_1.CLR的GC就是内存管理机制,我们写程序不需要关心内存的使用,因为这些都是CLR帮我们做了。
//4_1_1.程序在堆里保存3个对象
//4_1_2.后来程序中,其中一个对象不再被程序使用了
//4_1_3.垃圾收集器发现无主对象释放它
//4_1_4.垃圾收集之后,被释放的对象的内存可以被重用
//十一、值类型和引用类型
//1.类型被分为两种:
//1_1.值类型(整数,bool struct char 小数)--存储在栈
//1_2.引用类型(string 数组 自定义的类,内置的类)--存储在堆和栈-(存储数在堆-引用数据在栈)
//2.值类型只需要一段单独的内存,用于存储实际的数据,(单独定义的时候放在栈中)
//3.引用类型需要两段内存
//3_1.第一段存储实际的数据,它总是位于堆中
//3_2.第二段是一个引用,指向数据在堆中的存放位置,是放在栈当中的
static void
Test3() {
string name = "siki";
string name2 = "taikr";//当我们使用引用类型赋值的时候,其实是赋值的引用类型的引用
}
//如果数组是一个值类型的数组,那么数组中直接存储值,
//如果是一个引用类型的数组(数组中存储的是引用类型),那么数组中存储的是引用(内存地址)
static void Test4() {
Vector3[] vArray = new Vector3[] { new Vector3(), new Vector3(), new Vector3() };
Vector3 v2 = vArray[0];
vArray[0].X = 100;
v2.X = 333;
Console.WriteLine(vArray[0].X);
}
Test4();
//十二、继承
//1.继承是什么?
//很多类中有相似的数据,比如在一个游戏中,有Boss类,小怪类Enemy,这些类他们有很多相同的属性,也有不同的,
//这个时候我们可以使用继承来让这两个类继承自同一个类
//2.实现继承:
//表示一个类型派生于一个基类型,它拥有该基类型的所有成员字段和函数
//3.接口继承:
//表示一个类型只继承了函数的签名,没有继承任何实现代码
//4.什么时候使用接口继承
//在需要指定该类型具有某些可用的特性时,最好使用这种类型的继承。
//5.什么时候使用实现继承
//需要给现有的类型添加功能,或许多相关的类型共享一组重要的公共功能时,这种类型的继承非常有用
//6.多重继承?因此,C#不支持多重实现继承
//Boss boss = new Boss();
//boss.AI();//继承:父类里面所有的数据成员和函数成员都会继承到字类里面
//boss.Attack();
//十三、继承的注意
//1.父类声明的对象,可以使用子类去构造 字类声明的对象,不可以使用父类去构造
Enemy enemy = new Boss();//父类声明的对象,可以使用子类去构造 字类声明的对象,不可以使用父类去构造
//要用父类声明的enemy类型转为Boss类型----因为enemy虽然是父类的声明的,但enemy是子类构造的,所以enemy实际上还是子类的类型
//我们可以强制类型转换,转换成子类类型
//enemy.Attack();//如果这样去调用boss里的方法是不行的
//2.注意:一个对象是什么类型的,主要是看它是通过声明构造的-(类的强制类型转换,转换成子类类型)
//注意:要用父类声明的enemy类型转为Boss类型----因为enemy虽然是父类的声明的,但enemy是子类构造的,所以enemy实际上还是子类的类型,我们可以强制类型转换,转换成子类类型
Boss boss = (Boss)enemy;//我们可以强制类型转换,转换成子类类型
//boss.Attack();//这样就可以调用了
//3.父类可以进行构造,并使用自己的方法,但是用子类强制转换成父类类型,是不行
Enemy enemyTwo = new Enemy();
//Boss bossTwo = (Boss)enemyTwo;//这里会报错,一个对象是什么类型的,主要是看它是通过什么构造的,这里的enemyTwo使用了父类的构造函数,所以只有父类中的字段和方法,不能强制转为子类
//bossTwo.AI();这里不能使用
//十四、虚方法
//1.把一个基类函数声明为virtual,就可以在任何派生类中重写该函数:
//2.在派生类中重写另外一个函数时,要使用override关键字显示声明
Boss bossThree = new Boss();
//bossThree.Attack();
//bossThree.AI();//我们通过在构造子类的方法,不管在哪里调用都是调用重写之后的方法
Enemy enemythree = new Enemy();
//enemythree.AI();//我们通过在构造父类的方法,就调用的是原来的方法
//十五、隐藏方法
//如果签名(函数名或叫方法名)相同的方法在基类和派生类中都进行了声明,但是该方法没有分别声明为virtual和override,派生类就会隐藏基类方法(要使用new关键字进行声明)
Enemy bossFour = new Boss();//父类去声明的话,就是父类的方法
bossFour.AI();//子类去声明,就是字类的方法
//十六、this和base关键字
//1.this可以访问当前类,包括继承的类中定义的字段,属性和方法,有没有this都可以访问,有this可以让IDE-VS编译器给出提示
//2.base可以调用父类中的公有方法和字段,有没有base都可以访问,但是加上base.IED工具会给出提示,把所有可以调用的字段和方法罗列出来方便选择
//十七、抽象类
//1.C#允许把类和函数声明为 abstract
//2.抽象类的特点
//2_1.抽象类不能实例化,
//2_2.抽象类可以包含普通函数和抽象函数,
//2_3.抽象函数就是只有函数定义没有函数体
//2_4.抽象函数本身也是虚拟的Virtual(只有函数定义,没有函数体实现)
//2_5.类是一个模板,那么抽象类就是一个不完整的模板,我们不能使用不完整的模板去构造对象
//Crow crow = new Crow();//这是可以输出的
//crow.Fly();
Bird bird = new Crow();//我们可以用抽象类去声明对象,但是不可以去构造
bird.Fly();
//十八、密封类和密封方法、什么时候使用 密封类和密封方法?
//1.C#允许把类和方法声明为 sealed
//2.对于类 ,这表示不能继承该类;对于方法表示不能重写该方法。
//3.防止重写某些类导致代码混乱、商业原因
//sealed class BaseClass//声明为密封的类无法被继承
BaseClass baseClass = new DerivedClass();
baseClass.Move();
//十九、派生类的构造函数
//1.在子类中调用父类的默认构造函数(无参)(会先调用父类的,然后是子类的)
//2.调用有参数的构造函数
//加上:base()表示,调用父类中无参的构造函数 :base()可以不写,它默认就是调用父类中无参的构造函数
DerivedClass o1 = new DerivedClass();//会先调用父类的,然后是子类的
DerivedClass o2 = new DerivedClass(1,2);//会先调用父类的,然后是子类的
//二十、修饰符
//1.修饰符,用表示类型或者成员的关键字。修饰符可以指定方法的可见性
//2.public和private修饰字段和方法的时候,表示该字段或者方法能不能通过对象去访问,只有public的才可以通过对象访问,private(私有的)只能在类模板内部访问
//3.protected当没有继承的时候跟private是一样的。当有继承的时候,protected表示可以被子类访问的字段或者方法(protected只有派生的类型,才可以访问)
//4.static可以修饰字段或者方法,修饰字段的时候,表示这个字段是静态的数据,叫做静态字段或者静态属性,修饰方法的时候,叫做静态方法,或者静态函数
BaseClass.a = 100;//使用static修饰的成员,只能通过类名访问
Console.WriteLine(BaseClass.a);
BaseClass.StaticFun();//当我们构造对象的时候,对象中只包含了普通的字段,不包含静态字段
//5.new:仅允许在嵌套类声明时使用,表明类中隐藏了由基类中继承而来的、与基类中同名的成员。
//6.internal:只有其所在类才能访问。
//7.virtual声明 override去使用-虚方法
//8.abstract:抽象类,不允许建立类的实例。
//9.sealed:密封类,不允许被继承。
//二十一、定义和实现接口
//1.定义接口(飞翔功能) public interface IFlyHandler{}
//使用public class Type1Enemy:IFlyHandler{}
//2.接口的特点
//2_1.定义一个接口在语法上跟定义一个抽象类完全相同,但不允许提供接口中任何成员的实现方式,一般情况下,接口只能包含方法,属性,索引器和事件的声明。
//2_2.接口不能有构造函数,也不能有字段,接口也不允许运算符重载。
//2_3.接口定义中不允许声明成员的修饰符,接口成员都是公有的
//3.派生的接口
//class Type1Enemy : IA, IB//接口可以彼此继承,其方式和类的继承方式相同
//二十二、集合类 列表List
//当我们有很多类型一样的数据的时候,前面我们一般使用数组来进行管理,但是这样有个缺点就是数组的大小是固定的。
//如果我们很多类型一样的数据,比如游戏得分,我们可以集合类来进行管理,比如列表List,我们可以使用列表List很方便的添加数据,删除数据还有其他对数据的操作。
//1.创建列表(列表可以存储任何类型的数据,在创建列表对象的时候首先要指定你要创建的这个列表要存储什么类型的)(泛型)
//using System.Collections.Generic;//需要引用
//第一种
List<int> scoreList = new List<int>();//创建了一个空的列表,通过类型后面的<>来表示这个列表存储的数据的类型
//第二种
var scoreList1 = new List<int>(10);
//var scoreList1 = new List<int>() { 1,2,3};
//2.往列表中插入数据
scoreList1.Add(12);
scoreList1.Add(26);
scoreList1.Add(32);
scoreList1.Add(42);
//3.如何取得列表中的数据?列表中的数据跟数组有点相似,索引从0开始 ,可以通过索引来访问
Console.WriteLine(scoreList1[1]);
//4.Count、Capacity的使用
Console.WriteLine(scoreList1.Count);//获取Count存储数据的数组的长度
Console.WriteLine(scoreList1.Capacity); //Capacity设置或获取容量
//5.遍历列表有两种方式:
//5_1.for循环,遍历所有的索引,通过索引访问列表中的元素
for (int n = 0; n < scoreList1.Count; n++) {
//Console.Write(scoreList1[n] + " ");
}
//5_2.foreach遍历
foreach ( int b in scoreList1) {
//Console.Write( b + " ");
}
//二十三、操作列表的属性和方法
var scoreLista = new List<int>();
scoreLista.Add(100);
scoreLista.Add(200);
scoreLista.Add(300);//添加元素
scoreLista.Add(200);
foreach (int c in scoreLista) {
Console.Write(c + " ");
}
Console.WriteLine();
scoreLista.Insert(1, -1); //在下标为1的地方,插入-1,方法插入元素
foreach (int c in scoreLista)
{
Console.Write(c + " ");
}
Console.WriteLine();
scoreLista.RemoveAt(0);//移除了下标为0的内容也就是100,被移除了
foreach (int c in scoreLista)
{
Console.Write(c + " ");
}
Console.WriteLine();
int indexNum = scoreLista.IndexOf(300);
Console.WriteLine(indexNum);//2是这个列表中存在300,返回下标为2 -1表示不存在
Console.WriteLine(scoreLista.LastIndexOf(200));//返回3,这个列表中存在2个200,它会从索引开始到最后一位,并返回最后一次的下标,所以是3
//1.Capacity获取容量大小
//2.Add()方法添加元素
//3.Insert()方法插入元素
//4.[index]访问元素
//5.Count属性访问元素个数
//6.RemoveAt()方法移除指定位置的元素
//7.IndexOf()方法取得一个元素所在列表中的索引位置
//LastIndexOf()上面的方法是从前往后搜索,这个是从后往前搜索,搜索到满足条件的就停止
//上面的两个方法,如果没有找到指定元素就返回 - 1
//8.Sort()对列表中是元素进行从小到大排序
//二十三、泛型
//1.泛型是什么?
//过参数化类型来实现在同一份代码上操作多种数据类型。利用“参数化类型”将类型抽象化,从而实现灵活的复用。
//2.泛型类定义
//定义一个泛型类就是指的是,定义一个类,这个类中某些字段的类型是不确定的,这些类型可以在类构造的时候确定下来,举例:
//创建一个类处理int类型和double类型的相加
var o3 = new ClassA<int>(6,6);//当我们利用泛型类构造的时候,需要制定泛型的类型
string s = o3.GetSun();
Console.WriteLine(s);
//3.泛型的方法
//定义泛型方法就是定义一个方法,这个方法的参数的类型可以是不确定的,当调用这个方法的时候再去确定方法的参数的类型。
//实现任意类型组拼成字符串的方法
Console.WriteLine(GetSum<int>(1,2));
Console.WriteLine(GetSum<double>(1.2, 1.3));
Console.WriteLine(GetSum("泛型", "方法"));
//4.使用泛类型和索引器实现集合类MyList
MyList<int> mylist = new MyList<int>();
mylist.Add(234);
mylist.Add(14);
mylist.Add(24);
mylist.Add(274);//增加
mylist.Add(66);//增加
mylist.RemoveAt(3);//删除下标第三个
mylist.Insert(1, 66);//插入
//5.索引器:通过[index]这种形式去访问数据,就是索引器
mylist[0] = 100;//改-通过索引器设置值
for (int y = 0; y < mylist.Count; y++)
{
//Console.WriteLine(mylist.GetTtem(y));
Console.WriteLine(mylist[y]);//通过索引器取值
}
Console.WriteLine(mylist.IndexOf(14));
Console.WriteLine(mylist.LastIndexOf(66));
mylist.Sort();
for (int y = 0; y < mylist.Count; y++)
{
Console.WriteLine(mylist[y]);//通过索引器取值
}
}
public static string GetSum<T>(T a,T b ) {
return a +""+ b;
}
}
class ClassA<T>
{ //T代表一个数据类型,当使用classA进行构造的时候,需要制定T的类型
private T a;
private T b;
public ClassA(T a, T b)
{
this.a = a;
this.b = b;
}
public string GetSun()
{
return a + "" + b;
}
}
}
这是Customer类
using System;
namespace 学习C_的中级编程
{
//类的定义
class Customer
{
//编程规范上面,习惯把所有的字段设置为private,只能在类的内部访问,不可以通过对象访问,那我们怎么进行访问呢?
//为字段提供set方法,来设置字段的值
public string name;//字段的声明
public string address;
public int age;
public string buyTime;
private float x, y, z;
public void Show()//方法的声明
{
Console.WriteLine("名字" + name);
Console.WriteLine("年龄" + age);
Console.WriteLine("地址" + address);
Console.WriteLine("购买时间" + buyTime);
}
public void SetX(float x) //为字段提供set方法,来设置字段的值
{//如果我们直接在方法内部访问同名的变量的时候,优先访问最近(形参)
this.x = x;//我们可以通过this.表示访问的是类的字段或方法
}
public float Length() {
return (float)x * 2;
}
}
}
Vector3类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 学习C_的中级编程
{
//类的定义
class Vector3//无参
{
private float x, y, z, length;
public Vector3()//有参-这里我们定义了一个构造函数,所以编译器不会提供给我们一个默认的无参的构造函数
{
Console.WriteLine("Vector3的构造函数被调用了");
}
public Vector3(float x, float y, float z) {
this.x = x;
this.y = y;
this.z = z;
length = Length();//赋值一个函数也可以
}
//当我们不写,任何构造函数的时候,编译器会提供给我们一个默认的无参的构造函数,
public void SetX(float x) //为字段提供set方法,来设置字段的值
{//如果我们直接在方法内部访问同名的变量的时候,优先访问最近(形参)
this.x = x;//我们可以通过this.表示访问的是类的字段或方法
}
public void SetY(float y) //为字段提供set方法,来设置字段的值
{//如果我们直接在方法内部访问同名的变量的时候,优先访问最近(形参)
this.y = y;//我们可以通过this.表示访问的是类的字段或方法
}
public void SetZ(float z) //为字段提供set方法,来设置字段的值
{//如果我们直接在方法内部访问同名的变量的时候,优先访问最近(形参)
this.z = z;//我们可以通过this.表示访问的是类的字段或方法
}
public float Length()
{
return (float)x + y + z;
}
//定义属性
public int MyIntPropety {
//1.set和get可以全部都有
//2.可以只有set方法,没有get块就不可以取值了
//3.可以有get方法,没有set块就不可以设置值了
set
{
Console.WriteLine("属性中的set块被调用");
Console.WriteLine("在set块中访问的值是:" + value);
}
get {
Console.WriteLine("属性中的get块被调用");
return 100;
}
}
//通过属性来访问字段
public float X {
set { x = value;}//通过属性X访问私有的变量x
get { return x; }//我们可以在前面加private,表示这个块只能在内部使用
}
public string Name { set;get; }//编译器会自动给我们提供一个字段,来存储name
private int age;
public int Age {
set {
//通过set方法,可以在设置值之前做一些验证功能,另外还有许多其他的功能待发掘
if (value >= 0)
{
age = value;
}
}
get
{
return age;
}
}
}
}
Enemy类
using System;
using System.Collections.Generic;
using System.Text;
namespace 学习C_的中级编程
{
class Enemy//基类型
{
private float hp;
private float speed;
public float Hp {
set { hp = value;}
get { return hp; }
}
public float Speed
{
set { speed = value; }
get { return speed; }
}
public void AI() {//基类的函数
//Move();//我们在子类里面重写虚函数之后,不管在哪里调用都是调用重写之后的方法
Console.WriteLine("这里是Enemy1的公有AI方法");
//this.speed = 200;this可以访问当前类,包括继承的类中定义的字段,属性和方法,有没有this都可以访问
}
public virtual void Move()//基类的函数 -- 把一个基类函数声明为virtual,就可以在任何派生类中重写该函数:
{
Console.WriteLine("这里是Enemy1的公有Move方法");
}
}
}
Boss类
using System;
using System.Collections.Generic;
using System.Text;
namespace 学习C_的中级编程
{
class Boss: Enemy//Boss是派生类 Enemy是基类 Boss继承了Enemy的所有成员字段和函数
{
public new void AI()//如果签名相同的方法在基类和派生类中都进行了声明,但是该方法没有分别声明为virtual和override,派生类就会隐藏基类方法
{//隐藏:只是把父类的方法隐藏了,看不到了,实际这个方法还在
Console.WriteLine("这里是Boss的移动AI的方法");
}
public override void Move()//虚方法的应该-在派生类中重写另外一个函数时,要使用override关键字显示声明
{
//base.Speed = 200;//base可以调用父类中的公有方法和字段,有没有base都可以访问
Console.WriteLine("这里是Boss的移动方法");
}
//要派生出来2个类
public void Attack() {
//AI();
//Move();
//Hp = 100;
//Hp = 100;//父类里面公有是数据和函数成员才可以在字类里面访问
Move();//这里因为虚方法---不会调用Enemy基类里面的方法,会调用重写的方法
Console.WriteLine("Boss正在进行攻击");
}
}
}
Type1Enemy类
using System;
using System.Collections.Generic;
using System.Text;
namespace 学习C_的中级编程
{
class Type1Enemy: IA, IB//接口可以彼此继承,其方式和类的继承方式相同
{
public void Method1() {
}
public void Method2()
{
}
}
}
Type2Enemy类
using System;
using System.Collections.Generic;
using System.Text;
namespace 学习C_的中级编程
{
class Type2Enemy: IFly
{
public void Fly()
{
}
public void MethodA()
{
}
}
}
Bird类
using System;
using System.Collections.Generic;
using System.Text;
namespace 学习C_的中级编程
{
abstract class Bird//C#允许把类和函数声明为 abstract--一个抽象类就是一个不完整的的模板
{
private float speed;
public void Eat() {
}
public abstract void Fly();//C#允许把类和函数声明为 abstract
}
}
Crow类
using System;
using System.Collections.Generic;
using System.Text;
namespace 学习C_的中级编程
{
class Crow:Bird//我们继承了一个抽象类的时候,必须去实现抽象方法
{
public override void Fly()//抽象方法override
{
Console.WriteLine("乌鸦在飞");
}
}
}
其他
using System;
using System.Collections.Generic;
using System.Text;
namespace 学习C_的中级编程
{
interface IFly{//接口的定义
void Fly();
void MethodA();
}
interface IA {
void Method1();
}
interface IB
{
void Method2();
}
//sealed class BaseClass//声明为密封的类无法被继承
class BaseClass
{
public static int a;//static表示静态的字段,通过对象是无法访问,只能通过类去访问
private int x;
protected int z;//protected只有派生的类型,才可以访问
public static void StaticFun() {
Console.WriteLine("这是静态的方法");
}
public BaseClass() {
Console.WriteLine("base class 无参的构造函数");
}
public BaseClass(int x)
{
this.x = x;
Console.WriteLine("x赋值完成");
}
public virtual void Move()//virtual跟override是配合的,是虚方法
{
Console.WriteLine("Move方法");
}
}
}
DerivedClass类
using System;
using System.Collections.Generic;
using System.Text;
namespace 学习C_的中级编程
{
class DerivedClass: BaseClass
{
private int y;
//public DerivedClass():base()//加上:base()表示,调用父类中无参的构造函数 :base()可以不写,它默认就是调用父类中无参的构造函数
public DerivedClass()
{
Console.WriteLine("DerivedClass 无参的构造函数");
}
public DerivedClass(int x,int y):base(x)// 把参数int x传递给父类的构造方法
{
this.y = y;
this.z = 100;//protected只有派生的类型,才可以访问z
Console.WriteLine("y赋值完成");
}
public sealed override void Move()//我们把重新的方法命名为密封方法,表示该方法不能被重写 //virtual跟override是配合的,是虚方法
{
Console.WriteLine("重新之后的Move方法");
}
}
}
MyList方法类
using System;
using System.Collections.Generic;
using System.Text;
namespace 学习C_的中级编程
{
//使用泛类型和索引器实现集合类MyList
class MyList<T>where T:IComparable//添加约束一个可比性的接口
{
private T[] array;
private int count = 0;
public MyList(int size) {
if(size >= 0){
array = new T[size];
}
}
public MyList() {
array = new T[0];
}
public int Capacity
{
get{ return array.Length; }
}
public int Count {
get { return count; }
}
//添加
public void Add(T item) {
if (Count == Capacity)//判断元素个数跟列表容量大小是否一样大,如果一样大,就说明数组容量不用 ,创建新的数组
{
if (Capacity == 0)
{
array = new T[4];//当数组长度为0的时候,创建一个长度为4的数组
}
else {
var newArray = new T[Capacity * 2];//当长度不为0的时候,我们创建一个长度为原来2倍的数组
Array.Copy(array, newArray, Count);//把旧数组中的元素复制到新的数组中,复制前count个 array--》newArray
array = newArray;
}
}
array[Count] = item;
count++;//元素个数自增
}
public T GetTtem(int index) {
if (index >= 0 && index <= count - 1)
{
return array[index];
}
else {
//Console.WriteLine("所以超出了范围");
throw new Exception("所以超出了范围");
}
}
//索引器
public T this[int index] {
get //当我们通过索引器取值的时候,会调用get块
{
return GetTtem(index);
}
set {
if (index >= 0 && index <= count - 1)
{
array[index] = value;
}
else
{
//Console.WriteLine("所以超出了范围");
throw new Exception("所以超出了范围");
}
}
}
//插入位置
public void Insert(int index, T item) {
if (index >= 0 && index <= count - 1)
{
if (Count == Capacity) { //容量不足 进行扩容
var newArray = new T[Capacity * 2];//当长度不为0的时候,我们创建一个长度为原来2倍的数组
Array.Copy(array, newArray, Count);//把旧数组中的元素复制到新的数组中,复制前count个 array--》newArray
array = newArray;
}
for (int i = Count - 1; i >= index; i--) {
array[i + 1] = array[i];//把i位置的值放在后面,就是向后移动一个单位
}
array[index] = item;
count++;
}
else {
throw new Exception("所以超出了范围");
}
}
//移除
public void RemoveAt(int index) {
if (index >= 0 && index <= count - 1)
{
for (int i = index + 1; i < count; i++)
{
array[i - 1] = array[i];
}
count--;
}
else {
throw new Exception("所以超出了范围");
}
}
//搜索
public int IndexOf(T item) {
for (int i = 0; i < count; i++) {
if (array[i].Equals(item)) {
return i;
}
}
return -1;
}
public int LastIndexOf(T item)
{
for (int i = count-1; i >=0; i++)
{
if (array[i].Equals(item))
{
return i;
}
}
return -1;
}
//排序-小-大//添加约束一个可比性的接口
public void Sort() {
for (int j = 0; j < count - 1; j++) {
for (int i = 0; i < Count - 1 - j; i++)
{
if (array[i].CompareTo(array[i + 1]) > 0)//CompareTo这个方法需要引用,不然不会有
{
T temp = array[i];
array[i] = array[i + 1];
array[i + 1] = temp;
}
}
}
}
}
}