抽象类
关键词abstract
//抽象方法的声明
abstract class Player(){
public abstract void Trian();
}
//子类里边
class FootballPlayer : Player
{
public override void Train()
{
Console.WriteLine("正在训练运球...");
Console.WriteLine("正在训练射门...");
}
}
虚方法和抽象的区别
(1)虚方法可以重写也可以不重写,抽象必须重写
(2)虚方法有方法体{}
抽象方法没有方法体
(3)抽象方法必须写在抽象类里
抽象方法是隐式的虚方法
抽象方法只能有声明不提供实际的实现
抽象方法必须被子类重写并实现,或使其子类依旧为抽象类
抽象方法的访问修饰符不能是private,不然就无法被子类访问了,也就无法重写了
小例子
/*
定义抽象类Emplyee:
类中属性:名字name,工号ID
类中抽象方法:
计算薪资CalculateSalary,工作内容WorkContent,赚钱MakeMoney。
定义非抽象类Manager继承自Emplyee,实现Emplyee当中的方法并使用。
*/
abstract class Emplyee
{
//定义抽象类
public abstract string name();
public abstract int id();
//抽象方法
public abstract void CalculateSalary();
public abstract void WorkContent();
public abstract void MakeMoney();
}
class Manager : Emplyee
{
public override void CalculateSalary()
{
}
public override int id()
{
return 0;
}
public override void MakeMoney()
{
}
public override string name()
{
return " ";
}
public override void WorkContent()
{
}
}
静态类
静态成员
静态成员变量是和类相关联的,可以作为类中“共”有的变量(是一个共性的表现),静态成员不依赖特定对象的存在,访问的时候通过类来操作的。
通过类名去点他的名字
特点
静态成员随着类的加载而加载,无论对一个类创建多少个实例,静态成员都只有一个副本
静态方法可以被重载但不能被重写,因为他们是属于类,不属于任何实例的
静态成员由类名通过点语法调用,非静态成员是由对象来调用
静态方法只能访问静态成员,包括静态成员变量和静态方法;实例方法可以访问实例成员变量与实例方法,也可以访问静态成员
/*
给静态类Mathf添加以下方法
(1)求两个数的最大值MaxValue
(2)求两个数的乘积MulValue
(3)求某个数的阶乘
*/
static class Mathf
{
public static int MaxValue(int a,int b)
{
int c = a > b ? a : b;
return c;
}
public static int MulValue(int a ,int b)
{
int c = a * b;
return c;
}
public static void JieCheng()
{
}
}
静态构造函数
class Hero
{
public Hero(string name, int HP, string type)
{
//实例构造函数
this.name = name;
this.HP = HP;
this.type = type;
}
//静态构造函数
static Hero()
{
Console.WriteLine("Hero类的静态构造函数");
}
}
静态构造函数是固定格式,不能有修饰符,不能带任何参数
一个类只能有一个静态构造函数,即静态构造函数不可以重载
静态构造函数不可被直接调用,当创建类实例或访问任何静态成员时,静态构造函数会被自动调用,并且只执行一次
一个类的静态构造函数在它的所有派生类的静态构造函数执行之后执行
设计模式
设计模式是那些大佬们总结出来的思路,我们主要用的是单例模式,其他的也用,到后面会说
单例模式
某个类只有一个实例
单例模式的三要点:
(1)某个类只能有一个实例
(2)必须自行创建这个实例
(3)必须自行向外界提供这个实例
单例模式是一套写法的,并不是固定的,他是一种思想,能实现就行
默认构造使用private修饰
内建该类的静态实例
静态构造方法中给该静态实例做初始化
对外提供获取该静态实例的方法
//单例实现
public class SingleTon
{
private SingleTon() { } //构造方法必须私有化
private static SingleTon instance; //定义静态实例
public static SingleTon GetInstance()
{
//对外提供获取该实例的接口
if (instance == null)
{
instance = new SingleTon();
}
return instance;
}
}
举个例子
class AudioManager{
//构造私有化,禁止外界new对象
private AudioManager(){}
//静态变量
private static AudioManager instance = null;
//对外开放一个静态方法
public static AudioManager GetInstance(){
if(instance == null){
instance = new AudioManager();
}
return instance;
}
//播放声音
public void PlayBgm(){
}
//停止声音
public void Stop(){
}
}
class Program{
static void Main(string[] args){
AudioManager manager = AudioManager.GetInstance();
manager.PlayBgm();
}
//再随便创建一个方法
static void Func(){
AudioManager manager = AudioManager.GetInstance();
manager.Stop();//这样两个方法是同一个对象
}
}
什么时候该用静态?什么时候该用单例呢?
有关联的关系紧密的用单例,互不影响的用静态
第二种,用属性实现
class DataManager{
//构造私有化,禁止外界new对象
private DataManager(){}
//静态变量
private static DataManager instance;//instance实例的意思
//对外开放一个静态方法
public static DataManager Instance{
get{
if(instance == null){
instance = new AudioManager();
}
return instance;
}
}
}
class Program{
static void Main(string[] args){
DataManager datamanager = DataManager.Instance;
}
}
在unity里通过回调函数它会自动调用 后面还会再提
class Class1 : MonoBehaviour
public static Class1 Instance;
void Awake(){
Instance = this;
}
void Start(){
}
举个例子
/*
定义一个GameData单例类
设置游戏时长、已过游戏关卡数等变量
试着设置更多符合单例性质的字段或方法
*/
using System;
using System.Collections.Generic;
using System.Text;
class GameDate
{
private GameDate() { }
private static GameDate instance;
public static GameDate GetInstance()
{
if (instance == null)
{
instance = new GameDate();
}
return instance;
}
}
索引器
class Person{
public string[] names = {"xiaoming","xiaohong","xiaogang"};
//索引器
//要public
//索引的什么类型,这里就是什么类型
//this[int index] 中括号代表着索引 在Main函数里传多少这里显示的就是多少
public string this[int index]{
set{
names[index] = value;
}
get{
return names[index];
}
}
}
class Program
{
static void Main(string[] args)
{
//正常写法
/*
Person person = new Person();
Console.WriteLine(person.names[0]);
*/
Person person = new Person();
person[0] = "aaa";
Console.WriteLine(person[0]);//Console.WriteLine(person.names[0]);都可以
}
}
命名空间/名称空间
就是解决名字相同的问题
举个例子
namespace Test1{
class Person{
}
}
namespace Test2{
class Person{
}
class Program
{
static void Main(string[] args)
{
Test1.Person person = new Test1.Person();
}
}
}
运算符重载
重定义或重载 C# 中内置的运算符。
重载运算符是具有特殊名称的函数,是通过关键字 operator 后跟运算符的符号来定义的。
class Person{
public int age = 5;
//运算符重载
public static Person operator + (Person p1, Person p2){
Person p = new Person();
p.age = p1.age + p2.age;
return p;
}
}
class Program
{
static void Main(string[] args)
{
Person p1 = new Person();
p1.age = 10;
//第二种写法多个值加逗号
Person p2 = new Person(){ age = 20 };
Person p3 = p1 + p2;
Console.WriteLine(p3.age);
}
}
接口
接口是什么:接口是一组包含了类或结构可以实现的功能的定义。
接口可以包含事件,索引器,方法和属性,但是不能包含字段。
接口是一个引用类型,只包含了功能的定义,不包含功能的实现
接口成员的访问级别是默认的(默认为public),不可以使用其他修饰词修饰
接口成员不能添加任何的访问修饰符
类的继承只能单继承,接口的实现支持多继承
语法:
//关键词interface 后面是规定 一般都是先加一个大写的I。然后再写名字
//方法体里只写要实现的事件,索引器,方法和属性
//继承该接口的类,再去实现该接口
interface I×××××××
{
public void attack();
}
接口一旦被实现,就必须实现接口当中的所有成员
接口无法直接进行实例化,因为其成员必须通过由实现接口的任何类或结构来实现
实现多接口时,用逗号隔开
相同点:
两者都不能被实例化
两者都包含了由其他类或结构继承或实现的抽象成员
不同点:
抽象类当中除了拥有抽象成员外还可以拥有非抽象成员;而接口中所有的所有成员都是抽象的
抽象成员可以使用修饰符修饰,接口当中接口成员访问级别是默认不可修改的,并且默认是public
接口当中不可以包含构造方法,析构方法,静态成员以及常量
C#类只支持单继承,接口支持多继承
注意:
这里解释一下,析构方法 析构方法是在程序即将结束时候运行的
C#里基本用不到,因为C#有自动回收机制
Person(){
}
//这个是析构函数
~Person(){
}