首页 > 学院 > 开发设计 > 正文

刨根问底U3D---关于Delegate的方方面面

2019-11-17 02:36:36
字体:
来源:转载
供稿:网友

刨根问底U3D---关于Delegate的方方面面

我是否需要阅读这篇文章

Code1:

1 PRivate delegate void BloodNumDelegate ();2 3 public delegate void ExpNumChangeDelegate (int _currentExpNum);4 5 public event ExpNumChangeDelegate mOnExpNumChangeDelegate;

Code2:

PlayerVoProxy.instance.mOnExpNumChangeDelegate += delegate(int _expNum){    Console.WriteLine ("阿呆收到, ExpNum is : {0}", _expNum);};

如果你可以很清楚明白上面两部分代码是什么意思,说明你已经很了解Delegate(至少比我了解:) ),

所以我想下面的文章也许对你的帮助不是很大. 不过如果某些地方你也有所疑惑,希望你能从我下面的文章中得到一些帮助.


这篇文章都包含哪些内容

这篇文章从最基本的Delegate开始介绍起,后续会引申到event, 匿名Delegate 及我个人对其使用的一点理解

提前需要阅读的文章

如果你像我当初一样对Delegate完全不理解,请先阅读

NET之美:.NET关键技术深入解析.NET之美:.NET关键技术深入解析 迷你书 中的 第3章 (C# 中的委托和事件).

(作者对Delegate理解的及其深入,我是比不上了 :()


什么是 Delegate

从观察者模式说起

观察者模式大家肯定都不陌生

using System;using System.Collections;namespace L1{    public class FakeBloodChangeDelegate    {        public ArrayList mAllFakeDelegateListener;        public FakeBloodChangeDelegate ()        {            mAllFakeDelegateListener = new ArrayList ();        }        public void addListener (IFakeBloodNumChangeDelegateListener _listener)        {            mAllFakeDelegateListener.Add (_listener);        }        public void upldateListener ()        {            foreach (IFakeBloodNumChangeDelegateListener listener in mAllFakeDelegateListener)            {                listener.onBloodNumChange ();            }        }    }}
using System;namespace L1{    public interface IFakeBloodNumChangeDelegateListener    {        void onBloodNumChange ();    }}
using System;namespace L1{    public class Idiot : IFakeBloodNumChangeDelegateListener    {        public Idiot ()        {        }        public void onBloodNumChange ()        {            Console.WriteLine ("Idiot --> onBloodNumChange");        }    }}

using System;namespace L1{    public class TestArea1    {        private FakeBloodChangeDelegate mFakeBloodChangeDelegate;        private Idiot mIdiot;        public TestArea1 ()        {        }        public void run ()        {            mFakeBloodChangeDelegate = new FakeBloodChangeDelegate ();            mIdiot = new Idiot ();            mFakeBloodChangeDelegate.addListener (mIdiot);            mFakeBloodChangeDelegate.upldateListener ();        }    }}

这是一个比较标准的观察者, idiot是监听的人,当主体(FakeBloodChangeDelegate)发生变化时候调用 updateListener方法告诉所有监听对象

Ok, 接下来让我们稍微对这个FakeBloodChangeDelegate类进行一个简单的封装, 为其创建一个Player对象,Blood是Player的一部分

using System;namespace L1{    public class FakePlayerVoProxy    {        public FakeBloodChangeDelegate bloodNumChangeListner;        private int mCurrentBloodNum = 0;        public FakePlayerVoProxy ()        {            bloodNumChangeListner = new FakeBloodChangeDelegate ();        }        public void addPlayerBlood (int _addNum)        {            mCurrentBloodNum += _addNum;            bloodNumChangeListner.upldateListener ();        }    }}

于是,主类中的调用及变为:

using System;namespace L1{    public class TestArea1    {        private FakePlayerVoProxy mPlayerVo;        private Idiot mIdiot;        public TestArea1 ()        {        }        public void run ()        {            mPlayerVo = new FakePlayerVoProxy ();            mIdiot = new Idiot ();            mPlayerVo.bloodNumChangeListner.addListener (mIdiot);            mPlayerVo.addPlayerBlood (10);        }    }}

运行一下代码,会得到和上面一样的输出。 毕竟其实只是简单的对FakeBloodChangeDelegate进行一个封装,没有改变任何的代码。

如果上面的例子可以完全理解,就让我们往下继续

Delegate 就是一个类

这个其实是一个很重要的信息,在上面提到的那本迷你书里面已经说的非常清楚了. 我之所以把代码蹩脚的写成这个模样其实也是为了说明这件事。

上面例子中的FakeBloodChangeDelegate,包括对应的Listener可以简化为一行代码

public delegate void BloodNumChangeDelegate ();

先抛开public不说, 后面用 delegate void BloodNumChangeDelegate(); 相当于就是告诉编辑器为你创建出 一个

FakeBloodChangeDelegate 和IFakeBloodNumChangeDelegateListener (其实这块是不准确的表达,不过目前可以先不要细纠结到时是怎么回事,当看完后面的内容后 可以回头再去看 上面我提到的那本迷你书,里面讲的很详细)

using System;namespace L1{    public class FakePlayerVoProxy    {        public delegate void BloodNumChangeDelegate ();        public BloodNumChangeDelegate bloodNumChangeListner;        private int mCurrentBloodNum = 0;        public FakePlayerVoProxy ()        {        }        public void addPlayerBlood (int _addNum)        {            mCurrentBloodNum += _addNum;            bloodNumChangeListner ();        }    }}

注意

public delegate void BloodNumChangeDelegate (); 这行表示创建了FakeBloodChangeDelegate 类其实和 FackPlayerVoProxy这里类没有任何关系,

完全可以单独建立一个文件,起名Apple,然后把这行放在那个Apple的类里面不过根据这个类(Delegate)创建对象时候你就不能写

public BloodNumChangeDelegate bloodNumChangeListner;

而要写

public Apple.BloodNumChangeDelegate bloodNumChangeListner;

个人关于Delegate的一点理解

因为是写AS出身(ActionSprite),所以对于回调函数一点都不陌生,而Delegate就可以理解为C#中的回调函数,唯一会比较费解的会是

public delegate void BloodNumChangeDelegate ();public BloodNumChangeDelegate bloodNumChangeListner;

这两行代码,这块的核心就是要理解 Delegate其实就是告诉编译器为你生成一个实现了观察者模式的类.


关于Delegate前面的Public修饰符

之前我在解释Delegate是怎么一回事时候,故意忽略掉了其前面的类修饰符 public. 这块其实还是很有文章的.对于Delegate或者回归本质,对于观察者模式,最主要的三个函数应该是

addListener, removeListener, updateListener

而OO的思想就是 一定要封装 对于外部监听者 只应该能访问到 addListener, removeListener 而upldateListner这个应该只有主类才可以做的事情.

让我们先退回到实现Delegate之前的例子上面,继续使用FakeBloodChangeDelegate ,

若要实现以上的需求,仅需要对应的将FakeBloodChangeDelegate改为private 并提供相应的public函数即可

using System;namespace L1{    public class FakePlayerVoProxy    {        private FakeBloodChangeDelegate mBloodNumChangeListner;        private int mCurrentBloodNum = 0;        public FakePlayerVoProxy ()        {            mBloodNumChangeListner = new FakeBloodChangeDelegate ();        }        public void addListener(IFakeBloodNumChangeDelegateListener _listener)        {            mBloodNumChangeListner.Add(_listener);        }        public void removeListener(IFakeBloodNumChangeDelegateListener _listener){//对应Remove代码}                 public void addPlayerBlood (int _addNum)        {            mCurrentBloodNum += _addNum;            bloodNumChangeListner.upldateListener ();        }    }}

这块应该很好理解吧? 所以呢如果使用Delegate去实现同样的操作及可以写成:

using System;namespace L1{    public class FakePlayerVoProxy    {        public delegate void BloodNumChangeDelegate ();        private BloodNumChangeDelegate bloodNumChangeListner;        private int mCurrentBloodNum = 0;        public FakePlayerVoProxy ()        {        }        public void addListener (?? _listener)        {            bloodNumChangeListner += _listener;        }                    public void addPlayerBlood (int _addNum)        {            mCurrentBloodNum += _addNum;            bloodNumChangeListner ();        }    }}

你会发现 在addListener这里 不知道该怎么写了(其实是可以写的,不过如果这块你都理解怎么写了也就不用再继续往下读啦 哈),这个 _listener应该是什么类型呢?


使用Event关键字

在推荐的那本迷你书里面(什么?! 还没看...) 已经把这块说的非常明白了, 为了封装Delegate,对外仅提供add,remove 但是不提供

update方法, 但是如果不写成public 又没办法对外访问,所以及产生了 Event这个关键字

using System;namespace L1{    public class FakePlayerVoProxy    {        public delegate void BloodNumChangeDelegate ();        public event BloodNumChangeDelegate bloodNumChangeListner;        private int mCurrentBloodNum = 0;        public FakePlayerVoProxy ()        {        }        public void addPlayerBlood (int _addNum)        {            mCurrentBloodNum += _addNum;            bloodNumChangeListner ();        }    }}

using System;namespace L1{    public class TestArea1    {        private FakePlayerVoProxy mPlayerVo;
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表