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理解的及其深入,我是比不上了 :()
從觀察者模式說起
觀察者模式大家肯定都不陌生
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;
新聞熱點
疑難解答