笔记10 事件、项目实战、结构体
回顾委托的写法
新建一个类Test.cs(顺序1)
在Program.cs里实例化一个Test (顺序2)
static void Main(string[] args)
{
//实例化一个Test
Test test = new Test();
Console.ReadKey();
}
写一个委托(delegate。顺序5)
参数重要的是类型必须与要保存的方法一致,叫什么名无所谓。
//先写个委托。名字是Add。两个参数重要的是必须是int类型,叫什么名无所谓。
public delegate void Add(int aaa, int bbb);
声明一个委托(顺序6)
//声明一个委托。Add是上面写的委托名字。add是委托类型的变量。
public Add add;
add这个变量与其他变量的区别:例如public int a;中,a是int类型的。
类比得,add是Add类型(方法类型)。
add相当于普通变量,只不过它里面就是保存个方法。
写一个构造方法(顺序4),调用有两种方法(顺序7)
法一:new一个Add,将方法当参数传给它
//构造方法
public Test()
{
//func(3, 4); 正常调用方法的方式:方法名称();
//法一:new一个Add,将方法当参数传给它 。
add = new Add(func);
add(3,4);
}
//结果:7
法二:利用+=和-=
public Test()
{
//法二:
add += func;
add(3,4);
}
//结果:7
写一个需要委托的方法(顺序3)
委托相当于函数指针,在c#里相当于一个变量,用来保存方法。
保存了方法,这个变量就能像方法一样使用了。
//这个方法就是传两个参,然后把两个参的和打印出来。
public void func(int a, int b)
{
Console.WriteLine(a + b);
}
事件(比委托多了一个evevt,图标是闪电)
事件是对委托的封装。
事件主要是相对于控件来说的。比如桌面开发,控件时用事件,回调时用委托。
对游戏开发来说,二者一样,而且用委托用的多,用事件用的少。
事件是在写了委托的基础上,进行的。比如在声明一个委托(顺序6)后,声明一个事件(顺序7)
声明一个委托(顺序6)
//声明一个委托。Add是上面写的委托名字。add是委托类型的变量。
public Add add;
声明一个事件(evevt。顺序7)
//声明一个事件,对委托的封装
public event Add addEvent;
调用方法(两种。顺序8)
法一:new一个Add,将方法当参数传给它
public Test()
{
//事件
addEvent = new Add(func);
addEvent(5, 6);
}
/*结果:7(委托的结果)
11(事件的结果) */
法二:利用+=和-=
public Test()
{
//事件
addEvent += func;
addEvent(5, 6);
}
/*结果:7(委托的结果)
11(事件的结果) */
项目实战
类:1、录音机 2、磁带(存一首歌/个)
位置:AudioPlayer.cs(内部)
磁带(顺序1)
//磁带。private封装
private AudioClip clip;
定时器(顺序3)
//定时器
System.Timers.Timer timer;
索引【初写最外层,补充1】
//索引
private int index;
播放回调{把歌词回调到最外层。顺序a:声明委托}
/*播放回调(委托)。
AudioPlaying播放中的一个回调,void没有返回值,参数是char类型(字),每次传一个字过去。*/
public delegate void AudioPlaying(char c);
//声明一个委托。有了audioPlaying这个变量(委托类型的)。
public AudioPlaying audioPlaying;
/*声明一个委托audioPlaying,用来保存上面void AudioPlaying(char c)这个结构的一个方法。
这个方法返回值,参数是char类型(字)。*/
结束播放回调
//结束播放回调
public delegate void AudioEnd(string name);
public AudioEnd audioEnd;
构造方法(顺序4。实例化定时器,到时触发事件)
//构造方法
public AudioPlayer()
{
//实例化定时器(毫秒。1秒=1000毫秒)500即每隔半秒出一个字
timer = new System.Timers.Timer(500);
//到时触发事件
timer.Elapsed += playing;
/*写完等于号,按两下Tab键,会自动出现右边Timer_Elapsed以及下面的方法。
我们给它改个名叫playing*/
}
播放中,定时器触发的方法(绑定定时器)【初写最外层,补充:3:播放磁带里的内容】{把歌词回调到最外层。顺序b}
上面的到时触发事件,写完等于号,按两下Tab键,会自动出现此方法。
我们给它改个名叫playing。
//播放中,定时器触发的方法(绑定定时器)。只要开始播放,没隔半秒调用这个方法
private void playing(object sender, System.Timers.ElapsedEventArgs e)
{
/*播放磁带里的内容(补充)。因为要一个字一个字的播放,所以需要索引。
播到哪里?注意不能越界*/
if(index < clip.Content.Length)
{
//Console.Write(clip.Content[index++]); //把歌词写出来
/*此时已经可以在程序里看到歌词一个字一个字出现,
但应该把歌词回调到最外层,便要用到委托了。*/
//把歌词回调到最外层{顺序b}
if (audioPlaying != null)
{
//如果这个audioPlaying不为空,即委托存在,调用委托
audioPlaying(clip.Content[index++]);
//这个audioPlaying委托保存的方法在哪里?写在最外层。
}
} else
{
//播放结束
Stop();
}
}
写个方法,装载磁带(顺序2)
//写个方法,装载磁带。外界可以传进来AudioClip clip(即顺序1的)
public void LoadClip(AudioClip clip)
{
/*由于这里的clip和顺序1的clip重名,所以下面用this区分。
有this的是当前类的变量,无this的是参数*/
this.clip = clip;
}
播放【初写最外层,补充2:请空索引】
//播放
public void Play()
{
//如果有磁带,播放。clip加载磁带
if (clip != null)
{
//请空索引(补充)。确保每次播放从0开始
index = 0;
timer.Start();
//如果存在播放回调,就调用回调
if(audioStar != null)
{
audioStar(clip.Name); //把歌名传出去
}
}
}
停止
//停止
public void Stop()
{
//如果有磁带,播放。clip加载磁带
if(clip != null)
{
timer.Stop();
//如果存在结束回调,就调用回调
if(audioEnd != null)
{
audioEnd(clip.Name);
}
}
}
位置:Program.cs(最外层)
录音机
//录音机
public static AudioPlayer player;
如果是多盘磁带,则需补充磁带及其索引
//磁带
public static AudioClip[] clips;
//当前磁带索引
public static int index = 0;
调用方法{把歌词回调到最外层。顺序d}
static void Main(string[] args)
{
//创建录音机
player = new AudioPlayer();
//播放委托。把歌词回调到最外层{顺序d}
player.audioPlaying = new AudioPlayer.AudioPlaying(playing);
//开始播放委托
player.audioStar = new AudioPlayer.AudioStar(StartPlay);
//结束委托
player.audioEnd = new AudioPlayer.AudioEnd(EndPlay);
//创建磁带
AudioClip clip = new AudioClip("冰雨", "冷冷的冰雨在脸上胡乱地拍");
//加载磁带
player.LoadClip(clip);
//播放
player.Play();
Console.ReadKey();
}
多盘磁带循环,需将上面的创建磁带、加载磁带做如下修改
//创建磁带
clips = new AudioClip[3];
clips[0] = new AudioClip("冰雨", "冷冷的");
clips[1] = new AudioClip("小苹果", "你是我的");
clips[2] = new AudioClip("凉凉", "凉凉夜色");
//加载磁带
player.LoadClip(clips[index++]);
播放中的方法。{把歌词回调到最外层。顺序c}
//播放中的方法。委托要保存的方法
public static void playing(char word)
{
Console.Write(word);
}
开始播放的方法。
//开始播放的方法。传过来歌曲名称
public static void StartPlay(string name)
{
Console.WriteLine("开始播放:" + name);
}
结束播放的方法(如果是多盘磁带,需在下面补充)
//结束播放
public static void EndPlay(string name)
{
Console.WriteLine(""); //打印空的字符串。此处是换行的作用
Console.WriteLine("结束播放:" + name);
//如果还有下一盘磁带,换磁带播放(补充)
if (index < clips.Length)
{
player.LoadClip(clips[index++]);
player.Play();
}
}
示意图
结构体
类(属于引用类型)
结构体struct(属于值类型)
特点:不能继承,没有多态。
作用:用来储存简单数据的。
与类的区别:结构体不需要new。
class Test
{
void func2()
{
//结构体不需要new,声明出来就可以用
Enemy enemy;
enemy.Name = "东方不败";
Enemy enemy2 = enemy;
enemy.Name = "林平之";
Console.WriteLine(enemy.Name);
}
}
//结构体(值类型)
struct Enemy
{
public string Name;
}