出处:http://blog.csdn.net/u010019717
author:孙广东 时间:2015.3.21 23:00
不使用C#中的event关键字: 只是使用delegate和hashtable 进行事件的分发。
基本库如下:
namespace EventDispatcher
{
/// <summary>
/// IEvent接口
/// </summary>
public interface IEvent
{
/// <summary>
/// Gets or sets the type.
/// </summary>
/// <value>
/// type类型.
/// </value>
string type { get; set;}
/// <summary>
/// Gets or sets the target.
/// </summary>
/// <value>
/// target目标.
/// </value>
object target { get; set; }
}
}namespace EventDispatcher
{
/// <summary>
/// 事件事件接口
/// </summary>
public class Event : IEvent
{
// GETTER / SETTER
/// <summary>
/// The _type_string.
/// </summary>
private string _type_string;
string IEvent.type {
get
{
return _type_string;
}
set
{
_type_string = value;
}
}
/// <summary>
/// The _target_object.
/// </summary>
private object _target_object;
object IEvent.target {
get
{
return _target_object;
}
set
{
_target_object = value;
}
}
///<summary>
/// Constructor
///</summary>
public Event (string aType_str )
{
//
_type_string = aType_str;
}
/// <summary>
/// Deconstructor
/// </summary>
//~Event ( )
//{
// Debug.Log ("Event.deconstructor()");
//}
}
}namespace EventDispatcher
{
/// <summary>
/// IEventDispatcher 事件分发接口,添加移除分发
/// </summary>
public interface IEventDispatcher
{
/// <summary>
/// 添加事件监听
/// </summary>
/// <returns><c>true</c>, 如果事件成功被监听, <c>false</c> 失败 </returns>
/// <param name="aEventType_string">A event type_string.</param>
/// <param name="aEventDelegate">一个事件委托</param>
bool addEventListener(string aEventType_string, EventDelegate aEventDelegate);
/// <summary>
/// 添加事件监听
/// </summary>
/// <returns><c>true</c>, 如果事件成功被监听, <c>false</c> 失败 </returns>
/// <param name="aEventType_string">A event type_string.</param>
/// <param name="aEventDelegate">一个事件委托</param>
/// <param name="eventDispatcherAddMode">Event dispatcher add mode.</param>
bool addEventListener(string aEventType_string, EventDelegate aEventDelegate, EventDispatcherAddMode eventDispatcherAddMode);
/// <summary>
/// 是否有这个事件监听
/// </summary>
/// <returns><c>true</c>, 这个监听已经有了, <c>false</c> 没有.</returns>
/// <param name="aEventType_string">A event type_string.</param>
/// <param name="aEventDelegate">一个事件委托</param>
bool hasEventListener(string aEventType_string, EventDelegate aEventDelegate);
/// <summary>
/// 移除事件监听
/// </summary>
/// <returns><c>true</c>, 被成功移除 <c>false</c> 失败</returns>
/// <param name="aEventType_string">A event type_string.</param>
/// <param name="aEventDelegate">一个事件委托</param>
bool removeEventListener(string aEventType_string, EventDelegate aEventDelegate);
/// <summary>
/// 移除所有事件监听
/// </summary>
/// <returns><c>true</c>, 成功, <c>false</c> 失败 </returns>
bool removeAllEventListeners();
/// <summary>
/// 分发广播事件
/// </summary>
/// <returns><c>true</c>, 成功, <c>false</c> 失败</returns>
/// <param name="aIEvent">A I event.</param>
bool dispatchEvent(IEvent aIEvent);
}
}// C# unity事件管理器 在哈希表中使用字符串,对委托和事件管理
// 不知道他们何时何地declared/defined 也允许使用事件。
using UnityEngine;
using System.Collections;
namespace EventDispatcher
{
/// <summary>
/// Event delegateN事件委托
/// </summary>
public delegate void EventDelegate ( IEvent iEvent );
/// <summary>
/// Event listening mode.
/// </summary>
public enum EventDispatcherAddMode
{
DEFAULT,
SINGLE_SHOT
}
public class EventDispatcher : IEventDispatcher
{
/// <summary>
/// The mom_serialized object.
/// </summary>
private Hashtable _eventListenerDatas_hashtable = new Hashtable();
/// <summary>
/// The _target_object.
/// </summary>
private object _target_object;
///<summary>
/// Constructor
///</summary>
public EventDispatcher (object aTarget_object )
{
//
_target_object = aTarget_object;
}
/// <summary>
/// Deconstructor
/// </summary>
//~EventDispatcher ( )
//{
// Debug.Log ("EventDispatcher.deconstructor()");
//}
/// <summary>
/// Adds the event listener.
/// </summary>
/// <returns>
/// The event listener.
/// </returns>
/// <param name=‘aEventName_string‘>
/// If set to <c>true</c> a event name_string.
/// </param>
/// <param name=‘aEventDelegate‘>
/// If set to <c>true</c> a event delegate.
/// </param>
public bool addEventListener(string aEventName_string, EventDelegate aEventDelegate)
{
return addEventListener (aEventName_string, aEventDelegate, EventDispatcherAddMode.DEFAULT);
}
/// <summary>
/// Adds the event listener.
/// </summary>
/// <returns>
/// The event listener.
/// </returns>
/// <param name=‘aEventName_string‘>
/// If set to <c>true</c> a event type_string.
/// </param>
/// <param name=‘aEventDelegate‘>
/// If set to <c>true</c> a event delegate.
/// </param>
/// <param name=‘aEventDispatcherAddMode‘>
/// If set to <c>true</c> event listening mode.
/// </param>
public bool addEventListener(string aEventName_string, EventDelegate aEventDelegate, EventDispatcherAddMode aEventDispatcherAddMode)
{
//
bool wasSuccessful_boolean = false;
//
object aIEventListener = _getArgumentsCallee(aEventDelegate);
//
if (aIEventListener != null && aEventName_string != null) {
// OUTER
string keyForOuterHashTable_string = _getKeyForOuterHashTable (aEventName_string);
if (!_eventListenerDatas_hashtable.ContainsKey(keyForOuterHashTable_string) ) {
_eventListenerDatas_hashtable.Add(keyForOuterHashTable_string, new Hashtable());
}
// INNER
Hashtable inner_hashtable = _eventListenerDatas_hashtable[keyForOuterHashTable_string] as Hashtable;
EventListenerData eventListenerData = new EventListenerData (aIEventListener, aEventName_string, aEventDelegate, aEventDispatcherAddMode);
//
string keyForInnerHashTable_string = _getKeyForInnerHashTable (eventListenerData);
if (inner_hashtable.Contains(keyForInnerHashTable_string)) {
//THIS SHOULD *NEVER* HAPPEN - REMOVE AFTER TESTED WELL
Debug.Log("TODO (FIX THIS): Event Manager: Listener: " + keyForInnerHashTable_string + " is already in list for event: " + keyForOuterHashTable_string);
} else {
// ADD
inner_hashtable.Add(keyForInnerHashTable_string, eventListenerData);
wasSuccessful_boolean = true;
//Debug.Log (" ADDED AT: " + keyForInnerHashTable_string + " = " + eventListenerData);
}
}
return wasSuccessful_boolean;
}
/// <summary>
/// Hases the event listener.
/// </summary>
/// <returns>
/// The event listener.
/// </returns>
/// <param name=‘aIEventListener‘>
/// If set to <c>true</c> a I event listener.
/// </param>
/// <param name=‘aEventName_string‘>
/// If set to <c>true</c> a event name_string.
/// </param>
/// <param name=‘aEventDelegate‘>
/// If set to <c>true</c> a event delegate.
/// </param>
public bool hasEventListener(string aEventName_string, EventDelegate aEventDelegate)
{
//
bool hasEventListener_boolean = false;
//
object aIEventListener = _getArgumentsCallee(aEventDelegate);
// OUTER
string keyForOuterHashTable_string = _getKeyForOuterHashTable (aEventName_string);
if (_eventListenerDatas_hashtable.ContainsKey(keyForOuterHashTable_string)) {
// INNER
Hashtable inner_hashtable = _eventListenerDatas_hashtable[keyForOuterHashTable_string] as Hashtable;
string keyForInnerHashTable_string = _getKeyForInnerHashTable (new EventListenerData (aIEventListener, aEventName_string, aEventDelegate, EventDispatcherAddMode.DEFAULT));
//
if (inner_hashtable.Contains(keyForInnerHashTable_string)) {
hasEventListener_boolean = true;
}
}
return hasEventListener_boolean;
}
/// <summary>
/// Removes the event listener.
/// </summary>
/// <returns>
/// The event listener.
/// </returns>
/// <param name=‘aIEventListener‘>
/// If set to <c>true</c> a I event listener.
/// </param>
/// <param name=‘aEventName_string‘>
/// If set to <c>true</c> a event name_string.
/// </param>
/// <param name=‘aEventDelegate‘>
/// If set to <c>true</c> a event delegate.
/// </param>
public bool removeEventListener(string aEventName_string, EventDelegate aEventDelegate)
{
//
bool wasSuccessful_boolean = false;
//
if (hasEventListener (aEventName_string, aEventDelegate)) {
// OUTER
string keyForOuterHashTable_string = _getKeyForOuterHashTable (aEventName_string);
Hashtable inner_hashtable = _eventListenerDatas_hashtable[keyForOuterHashTable_string] as Hashtable;
//
object aIEventListener = _getArgumentsCallee(aEventDelegate);
// INNER
string keyForInnerHashTable_string = _getKeyForInnerHashTable (new EventListenerData (aIEventListener, aEventName_string, aEventDelegate, EventDispatcherAddMode.DEFAULT));
inner_hashtable.Remove(keyForInnerHashTable_string);
wasSuccessful_boolean = true;
}
return wasSuccessful_boolean;
}
/// <summary>
/// Removes all event listeners.
/// </summary>
/// <returns>
/// The all event listeners.
/// </returns>
public bool removeAllEventListeners()
{
//
bool wasSuccessful_boolean = false;
//TODO, IS IT A MEMORY LEAK TO JUST RE-CREATE THE TABLE? ARE THE INNER HASHTABLES LEAKING?
_eventListenerDatas_hashtable = new Hashtable();
return wasSuccessful_boolean;
}
/// <summary>
/// Dispatchs the event.
/// </summary>
/// <returns>
/// The event.
/// </returns>
/// <param name=‘aIEvent‘>
/// If set to <c>true</c> a I event.
/// </param>
public bool dispatchEvent(IEvent aIEvent)
{
//
bool wasSuccessful_boolean = false;
//
_doAddTargetValueToIEvent (aIEvent);
// OUTER
string keyForOuterHashTable_string = _getKeyForOuterHashTable (aIEvent.type);
int dispatchedCount_int = 0;
if (_eventListenerDatas_hashtable.ContainsKey(keyForOuterHashTable_string)) {
// INNER
Hashtable inner_hashtable = _eventListenerDatas_hashtable[keyForOuterHashTable_string] as Hashtable;
IEnumerator innerHashTable_ienumerator = inner_hashtable.GetEnumerator();
DictionaryEntry dictionaryEntry;
EventListenerData eventListenerData;
ArrayList toBeRemoved_arraylist = new ArrayList ();
//
while (innerHashTable_ienumerator.MoveNext()) {
dictionaryEntry = (DictionaryEntry)innerHashTable_ienumerator.Current;
eventListenerData = dictionaryEntry.Value as EventListenerData;
//***DO THE DISPATCH***
//Debug.Log ("DISPATCH : ");
//Debug.Log (" n : " + eventListenerData.eventName );
//Debug.Log (" from : " + aIEvent.target );
//Debug.Log (" to : " + eventListenerData.eventListener );
//Debug.Log (" del : " + eventListenerData.eventDelegate + " " + (eventListenerData.eventDelegate as System.Delegate).Method.DeclaringType.Name + " " + (eventListenerData.eventDelegate as System.Delegate).Method.Name.ToString());
eventListenerData.eventDelegate (aIEvent);
//TODO - THIS IS PROBABLY FUNCTIONAL BUT NOT OPTIMIZED, MY APPROACH TO HOW/WHY SINGLE SHOTS ARE REMOVED
//REMOVE IF ONESHOT
if (eventListenerData.eventListeningMode == EventDispatcherAddMode.SINGLE_SHOT) {
toBeRemoved_arraylist.Add (eventListenerData);
}
//MARK SUCCESS, BUT ALSO CONTINUE LOOPING TOO
wasSuccessful_boolean = true;
dispatchedCount_int++;
}
//CLEANUP ANY ONE-SHOT, SINGLE-USE
EventListenerData toBeRemoved_eventlistenerdata;
for (int count_int = toBeRemoved_arraylist.Count -1; count_int >= 0; count_int --) {
toBeRemoved_eventlistenerdata = toBeRemoved_arraylist[count_int] as EventListenerData;
removeEventListener (toBeRemoved_eventlistenerdata.eventName, toBeRemoved_eventlistenerdata.eventDelegate);
}
}
return wasSuccessful_boolean;
}
/// <summary>
/// _dos the add target value to I event.
/// </summary>
/// <param name=‘aIEvent‘>
/// A I event.
/// </param>
/// <exception cref=‘System.NotImplementedException‘>
/// Is thrown when a requested operation is not implemented for a given type.
/// </exception>
public void _doAddTargetValueToIEvent (IEvent aIEvent)
{
aIEvent.target = _target_object;
}
public void OnApplicationQuit()
{
//TODO, DO THIS CLEANUP HERE, OR OBLIGATE API-USER TO DO IT??
_eventListenerDatas_hashtable.Clear();
}
private string _getKeyForOuterHashTable (string aEventName_string)
{
//SIMPLY USING THE EVENT NAME - METHOD USED HERE, IN CASE I WANT TO TWEAK THIS MORE...
return aEventName_string;
}
private string _getKeyForInnerHashTable (EventListenerData aEventListenerData)
{
//VERY UNIQUE - NICE!
return aEventListenerData.eventListener.GetType().FullName + "_" + aEventListenerData.eventListener.GetType().GUID + "_" + aEventListenerData.eventName + "_" + (aEventListenerData.eventDelegate as System.Delegate).Method.Name.ToString();
}
public object _getArgumentsCallee (EventDelegate aEventDelegate)
{
return (aEventDelegate as System.Delegate).Target;
}
}
}namespace EventDispatcher
{
/// <summary>
/// EventListenerData
/// </summary>
public class EventListenerData
{
/// <summary>
/// The _event listener.
/// </summary>
private object _eventListener;
public object eventListener
{
get
{
return _eventListener;
}
set
{
_eventListener = value;
}
}
/// <summary>
/// 事件名
/// </summary>
private string _eventName_string;
public string eventName
{
get
{
return _eventName_string;
}
set
{
_eventName_string = value;
}
}
/// <summary>
/// 事件委托
/// </summary>
private EventDelegate _eventDelegate;
public EventDelegate eventDelegate
{
get
{
return _eventDelegate;
}
set
{
_eventDelegate = value;
}
}
private EventDispatcherAddMode _eventListeningMode;
public EventDispatcherAddMode eventListeningMode
{
get
{
return _eventListeningMode;
}
set
{
_eventListeningMode = value;
}
}
///<summary>
/// Constructor
///</summary>
public EventListenerData (object aEventListener, string aEventName_string, EventDelegate aEventDelegate, EventDispatcherAddMode aEventListeningMode )
{
_eventListener = aEventListener;
_eventName_string = aEventName_string;
_eventDelegate = aEventDelegate;
_eventListeningMode = aEventListeningMode;
}
/// <summary>
/// Deconstructor
/// </summary>
//~EventListenerData ( )
//{
//Debug.Log ("EventListenerData.deconstructor()");
//}
}
}
使用的例子:新建两个游戏对象然后挂上脚本!
namespace EventDispatcher
{
/// <summary>
/// Test event.
/// </summary>
public class SampleEvent : Event
{
// GETTER / SETTER
/// <summary>
/// An example of event-specific data you can add in.
/// </summary>
private string _customValue_string;
public string customValue
{
get {
return _customValue_string;
}
set {
_customValue_string = value;
}
}
/// <summary>
/// The Event Type Name
/// </summary>
public static string SAMPLE_EVENT = "SAMPLE_EVENT";
/// <summary>
/// Initializes a new instance of the <see cref="com.rmc.projects.event_dispatcher.SampleEvent"/> class.
/// </summary>
/// <param name="aType_str">A type_str.</param>
public SampleEvent (string aType_str ) : base (aType_str)
{
}
/// <summary>
/// Releases unmanaged resources and performs other cleanup operations before the
/// <see cref="com.rmc.projects.event_dispatcher.SampleEvent"/> is reclaimed by garbage collection.
/// </summary>
//~SampleEvent ( )
//{
// Debug.Log ("SampleEvent.deconstructor()");
//}
}
}using UnityEngine;
namespace EventDispatcher
{
public class SampleObservedComponent : MonoBehaviour
{
/// <summary>
/// The event dispatcher.
/// </summary>
public EventDispatcher eventDispatcher;
/// <summary>
/// Initializes a new instance of the <see cref="com.rmc.projects.event_dispatcher.SampleObservedComponent"/> class.
/// </summary>
public SampleObservedComponent ()
{
eventDispatcher = new EventDispatcher (this);
}
///<summary>
/// Use this for initialization
///</summary>
public void Start ()
{
SampleEvent sampleEvent = new SampleEvent (SampleEvent.SAMPLE_EVENT);
sampleEvent.customValue = "foo";
Debug.Log ("Dispatching: SampleEvent " + sampleEvent);
eventDispatcher.dispatchEvent (sampleEvent);
}
/// <summary>
/// Raises the destroy event.
/// </summary>
public void OnDestroy ()
{
// CLEANUP MEMORY
eventDispatcher.removeAllEventListeners();
eventDispatcher = null;
}
}
}using UnityEngine;
namespace EventDispatcher
{
public class SampleObserverComponent : MonoBehaviour
{
/// <summary>
/// The sample observed game object.
/// </summary>
public SampleObservedComponent sampleObservedGameObject;
public void Start ()
{
/*
* 注意: 这里observer和observed是 MonoBehavior 子类
**/
sampleObservedGameObject.eventDispatcher.addEventListener (SampleEvent.SAMPLE_EVENT, _onSampleEvent);
}
void Update ()
{
//Debug.Log (sampleObservedGameObject.eventDispatcher);
}
/// <summary>
/// Raises the destroy event.
/// </summary>
public void OnDestroy ()
{
// CLEANUP MEMORY
sampleObservedGameObject.eventDispatcher.removeEventListener (SampleEvent.SAMPLE_EVENT, _onSampleEvent);
}
//--------------------------------------
// Events
//--------------------------------------
/// <summary>
/// _ons the sample event.
/// </summary>
/// <param name="aIEvent">A I event.</param>
public void _onSampleEvent (IEvent aIEvent)
{
Debug.Log ("\tListening: _onSampleEvent() aIEvent: " + aIEvent + " with customValue: " + (aIEvent as SampleEvent).customValue);
}
}
}原文:http://blog.csdn.net/u010019717/article/details/44537477