高级C#消息机制(Advanced CSharp Messenger)
来源:互联网 发布:积分软件哪个最好 编辑:程序博客网 时间:2024/06/14 16:26
目录(?)[+]
转载自 :http://wiki.Unity3D.com/index.PHP?title=Advanced_CSharp_Messenger
先进CSharp信使
作者:Ilya Suzdalnitski
内容
( 隐藏 ]- 1 描述
- 2 前言
- 2.1 MissingReferenceException背后的原因和解决方案
- 3 的信使
- 3.1 使用
- 3.1.1 事件监听器
- 3.1.2 注册一个事件侦听器
- 3.1.3 取消注册一个事件侦听器
- 3.1.4 广播事件
- 3.2 清理信使
- 3.2.1之上 永久的消息
- 3.3 Misc
- 3.3.1 记录所有消息
- 3.3.2 从其他使者
- 3.4 代码
- 3.4.1 Callback.cs
- 3.4.2 Messenger.cs
- 3.1 使用
描述
这是一个先进的c#版本的消息传递系统。 它会自动清理事件表在一个新的水平加载。 这将防止程序员意外调用销毁方法,从而有助于防止许多MissingReferenceExceptions。 这个消息传递系统是基于杆海德 CSharpMessenger 和马格努斯Wolffelt CSharpMessenger扩展 。
前言
在消息传递系统引入我们的项目( CSharpMessenger扩展 )我们开始面临非常奇怪的错误。unity3d会把MissingReferenceExceptions每次广播消息。 它会说,类,消息处理程序中声明,被毁。 问题从哪里来的,没有一个合理的解释。 然而将消息处理程序代码在try - catch块解决了这个问题。 我们明白,这不是一个好的解决方案有成百上千的try - catch块在我们的代码。 我们花了一些时间来最后找出问题在哪里。
MissingReferenceException背后的原因和解决方案
原来,MissingReferenceException错误出现了,当一个新的水平加载当前(或重新加载)。 例如,我们有一个消息 “开始游戏” 宣布如下:
public class MainMenu : MonoBehaviour {void Start (){Messenger.AddListener("start game", StartGame);} void StartGame(){Debug.Log("StartGame called in" + gameObject); //This is the line that would throw an exception} void StartGameButtonPressed(){Messenger.Broadcast("start game");}}
乍一看,没有问题,但是水平加载后,Unity3d将抛出一个异常,称MainMenu已被摧毁。 然而没有代码,会破坏MainMenu脚本。
到底发生了什么:
- 我们添加了一个“开始游戏”对我们的信使消息侦听器。
- StartGameButtonPressed叫反过来播放“开始游戏”消息。
- 我们用Application.LoadLevel水平加载。
- 重复步骤1。
- 重复步骤2。
这里有eventTable使者的样子的相应的步骤:
- 在步骤1:{ “开始游戏”,mainMenu1 - > StartGame(); }
- 在步骤4:{ “开始游戏”,mainMenu1 - > StartGame(); } { “开始游戏”,mainMenu2 - > StartGame(); }
所以在第四步我们有两个相同的消息处理程序 “开始游戏” 消息——第一个是摧毁MainMenu对象(被破坏时重新加载一个级别),而第二种它为当前有效MainMenu对象。 事实证明,当我们广播的 “开始游戏” 消息后重新加载水平,信使调用——摧毁和有效的消息处理程序。 这就是MissingReferenceException来自的地方。
因此,显而易见——明确的解决方案 eventTable 卸货后的水平。 没有什么别的程序员是他清理桌子,它是自动完成的。
的信使
我们很高兴提供你一个高级版本的c#消息传递系统。
使用
事件监听器
void OnPropCollected( PropType propType ) {if (propType == PropType.Life)livesAmount++;}
注册一个事件侦听器
void Start() {Messenger.AddListener< Prop >( "prop collected", OnPropCollected );}
取消注册一个事件侦听器
Messenger.RemoveListener< Prop > ( "prop collected", OnPropCollected );
广播事件
public void OnTriggerEnter(Collider _collider) {Messenger.Broadcast< PropType > ( "prop collected", _collider.gameObject.GetComponent<Prop>().propType );}
清理信使
信使清理其eventTable时自动加载一个新的水平。 这将确保eventTable信使的清理,将从意想不到的MissingReferenceExceptions拯救我们。 如果你想手动清理经理eventTable,有这样一个选项通过调用Messenger.Cleanup();
永久的消息
如果你想要某个消息生存清理,马克与Messenger.MarkAsPermanent(字符串)。 这可能需要如果某个类响应消息播放来自不同的水平。
Misc
记录所有消息
用于调试目的,您可以设置 shouldLogAllMessages 国旗在信使为true。 这将记录所有调用信使。
从其他使者
快速改变旧的CSharpMessenger所有调用消息传递系统的先进,做以下步骤:
- 在MonoDevelop去搜索= >替换文件
- 在找到字段输入: 信使号<([^ < >]+)>([A-Za-z0-9_]+)。
- 在替换字段输入: 信使。< $ 1 > 2美元
- 选择范围:整体解决方案。
- 检查正则表达式搜索”复选框。
- 按更换按钮
代码
有两个文件所需的信使——工作 Callback.cs 和 Messenger.cs 。
Callback.cs
public delegate void Callback();public delegate void Callback<T>(T arg1);public delegate void Callback<T, U>(T arg1, U arg2);public delegate void Callback<T, U, V>(T arg1, U arg2, V arg3);
Messenger.cs
/* * Advanced C# messenger by Ilya Suzdalnitski. V1.0 * * Based on Rod Hyde's "CSharpMessenger" and Magnus Wolffelt's "CSharpMessenger Extended". * * Features: * Prevents a MissingReferenceException because of a reference to a destroyed message handler. * Option to log all messages * Extensive error detection, preventing silent bugs * * Usage examples: 1. Messenger.AddListener<GameObject>("prop collected", PropCollected); Messenger.Broadcast<GameObject>("prop collected", prop); 2. Messenger.AddListener<float>("speed changed", SpeedChanged); Messenger.Broadcast<float>("speed changed", 0.5f); * * Messenger cleans up its evenTable automatically upon loading of a new level. * * Don't forget that the messages that should survive the cleanup, should be marked with Messenger.MarkAsPermanent(string) * */ //#define LOG_ALL_MESSAGES//#define LOG_ADD_LISTENER//#define LOG_BROADCAST_MESSAGE#define REQUIRE_LISTENER using System;using System.Collections.Generic;using UnityEngine; static internal class Messenger {#region Internal variables //Disable the unused variable warning#pragma warning disable 0414//Ensures that the MessengerHelper will be created automatically upon start of the game.static private MessengerHelper messengerHelper = ( new GameObject("MessengerHelper") ).AddComponent< MessengerHelper >();#pragma warning restore 0414 static public Dictionary<string, Delegate> eventTable = new Dictionary<string, Delegate>(); //Message handlers that should never be removed, regardless of calling Cleanupstatic public List< string > permanentMessages = new List< string > ();#endregion#region Helper methods//Marks a certain message as permanent.static public void MarkAsPermanent(string eventType) {#if LOG_ALL_MESSAGESDebug.Log("Messenger MarkAsPermanent \t\"" + eventType + "\"");#endif permanentMessages.Add( eventType );} static public void Cleanup(){#if LOG_ALL_MESSAGESDebug.Log("MESSENGER Cleanup. Make sure that none of necessary listeners are removed.");#endif List< string > messagesToRemove = new List<string>(); foreach (KeyValuePair<string, Delegate> pair in eventTable) {bool wasFound = false; foreach (string message in permanentMessages) {if (pair.Key == message) {wasFound = true;break;}} if (!wasFound)messagesToRemove.Add( pair.Key );} foreach (string message in messagesToRemove) {eventTable.Remove( message );}} static public void PrintEventTable(){Debug.Log("\t\t\t=== MESSENGER PrintEventTable ==="); foreach (KeyValuePair<string, Delegate> pair in eventTable) {Debug.Log("\t\t\t" + pair.Key + "\t\t" + pair.Value);} Debug.Log("\n");}#endregion #region Message logging and exception throwing static public void OnListenerAdding(string eventType, Delegate listenerBeingAdded) {#if LOG_ALL_MESSAGES || LOG_ADD_LISTENERDebug.Log("MESSENGER OnListenerAdding \t\"" + eventType + "\"\t{" + listenerBeingAdded.Target + " -> " + listenerBeingAdded.Method + "}");#endif if (!eventTable.ContainsKey(eventType)) { eventTable.Add(eventType, null ); } Delegate d = eventTable[eventType]; if (d != null && d.GetType() != listenerBeingAdded.GetType()) { throw new ListenerException(string.Format("Attempting to add listener with inconsistent signature for event type {0}. Current listeners have type {1} and listener being added has type {2}", eventType, d.GetType().Name, listenerBeingAdded.GetType().Name)); } } static public void OnListenerRemoving(string eventType, Delegate listenerBeingRemoved) {#if LOG_ALL_MESSAGESDebug.Log("MESSENGER OnListenerRemoving \t\"" + eventType + "\"\t{" + listenerBeingRemoved.Target + " -> " + listenerBeingRemoved.Method + "}");#endif if (eventTable.ContainsKey(eventType)) { Delegate d = eventTable[eventType]; if (d == null) { throw new ListenerException(string.Format("Attempting to remove listener with for event type \"{0}\" but current listener is null.", eventType)); } else if (d.GetType() != listenerBeingRemoved.GetType()) { throw new ListenerException(string.Format("Attempting to remove listener with inconsistent signature for event type {0}. Current listeners have type {1} and listener being removed has type {2}", eventType, d.GetType().Name, listenerBeingRemoved.GetType().Name)); } } else { throw new ListenerException(string.Format("Attempting to remove listener for type \"{0}\" but Messenger doesn't know about this event type.", eventType)); } } static public void OnListenerRemoved(string eventType) { if (eventTable[eventType] == null) { eventTable.Remove(eventType); } } static public void OnBroadcasting(string eventType) {#if REQUIRE_LISTENER if (!eventTable.ContainsKey(eventType)) { throw new BroadcastException(string.Format("Broadcasting message \"{0}\" but no listener found. Try marking the message with Messenger.MarkAsPermanent.", eventType)); }#endif } static public BroadcastException CreateBroadcastSignatureException(string eventType) { return new BroadcastException(string.Format("Broadcasting message \"{0}\" but listeners have a different signature than the broadcaster.", eventType)); } public class BroadcastException : Exception { public BroadcastException(string msg) : base(msg) { } } public class ListenerException : Exception { public ListenerException(string msg) : base(msg) { } }#endregion #region AddListener//No parameters static public void AddListener(string eventType, Callback handler) { OnListenerAdding(eventType, handler); eventTable[eventType] = (Callback)eventTable[eventType] + handler; } //Single parameterstatic public void AddListener<T>(string eventType, Callback<T> handler) { OnListenerAdding(eventType, handler); eventTable[eventType] = (Callback<T>)eventTable[eventType] + handler; } //Two parametersstatic public void AddListener<T, U>(string eventType, Callback<T, U> handler) { OnListenerAdding(eventType, handler); eventTable[eventType] = (Callback<T, U>)eventTable[eventType] + handler; } //Three parametersstatic public void AddListener<T, U, V>(string eventType, Callback<T, U, V> handler) { OnListenerAdding(eventType, handler); eventTable[eventType] = (Callback<T, U, V>)eventTable[eventType] + handler; }#endregion #region RemoveListener//No parameters static public void RemoveListener(string eventType, Callback handler) { OnListenerRemoving(eventType, handler); eventTable[eventType] = (Callback)eventTable[eventType] - handler; OnListenerRemoved(eventType); } //Single parameterstatic public void RemoveListener<T>(string eventType, Callback<T> handler) { OnListenerRemoving(eventType, handler); eventTable[eventType] = (Callback<T>)eventTable[eventType] - handler; OnListenerRemoved(eventType); } //Two parametersstatic public void RemoveListener<T, U>(string eventType, Callback<T, U> handler) { OnListenerRemoving(eventType, handler); eventTable[eventType] = (Callback<T, U>)eventTable[eventType] - handler; OnListenerRemoved(eventType); } //Three parametersstatic public void RemoveListener<T, U, V>(string eventType, Callback<T, U, V> handler) { OnListenerRemoving(eventType, handler); eventTable[eventType] = (Callback<T, U, V>)eventTable[eventType] - handler; OnListenerRemoved(eventType); }#endregion #region Broadcast//No parameters static public void Broadcast(string eventType) {#if LOG_ALL_MESSAGES || LOG_BROADCAST_MESSAGEDebug.Log("MESSENGER\t" + System.DateTime.Now.ToString("hh:mm:ss.fff") + "\t\t\tInvoking \t\"" + eventType + "\"");#endif OnBroadcasting(eventType); Delegate d; if (eventTable.TryGetValue(eventType, out d)) { Callback callback = d as Callback; if (callback != null) { callback(); } else { throw CreateBroadcastSignatureException(eventType); } } } //Single parameter static public void Broadcast<T>(string eventType, T arg1) {#if LOG_ALL_MESSAGES || LOG_BROADCAST_MESSAGEDebug.Log("MESSENGER\t" + System.DateTime.Now.ToString("hh:mm:ss.fff") + "\t\t\tInvoking \t\"" + eventType + "\"");#endif OnBroadcasting(eventType); Delegate d; if (eventTable.TryGetValue(eventType, out d)) { Callback<T> callback = d as Callback<T>; if (callback != null) { callback(arg1); } else { throw CreateBroadcastSignatureException(eventType); } }} //Two parameters static public void Broadcast<T, U>(string eventType, T arg1, U arg2) {#if LOG_ALL_MESSAGES || LOG_BROADCAST_MESSAGEDebug.Log("MESSENGER\t" + System.DateTime.Now.ToString("hh:mm:ss.fff") + "\t\t\tInvoking \t\"" + eventType + "\"");#endif OnBroadcasting(eventType); Delegate d; if (eventTable.TryGetValue(eventType, out d)) { Callback<T, U> callback = d as Callback<T, U>; if (callback != null) { callback(arg1, arg2); } else { throw CreateBroadcastSignatureException(eventType); } } } //Three parameters static public void Broadcast<T, U, V>(string eventType, T arg1, U arg2, V arg3) {#if LOG_ALL_MESSAGES || LOG_BROADCAST_MESSAGEDebug.Log("MESSENGER\t" + System.DateTime.Now.ToString("hh:mm:ss.fff") + "\t\t\tInvoking \t\"" + eventType + "\"");#endif OnBroadcasting(eventType); Delegate d; if (eventTable.TryGetValue(eventType, out d)) { Callback<T, U, V> callback = d as Callback<T, U, V>; if (callback != null) { callback(arg1, arg2, arg3); } else { throw CreateBroadcastSignatureException(eventType); } } }#endregion} //This manager will ensure that the messenger's eventTable will be cleaned up upon loading of a new level.public sealed class MessengerHelper : MonoBehaviour {void Awake (){DontDestroyOnLoad(gameObject);} //Clean up eventTable every time a new level loads.public void OnLevelWasLoaded(int unused) {Messenger.Cleanup();}}
- 高级C#消息机制(Advanced CSharp Messenger)
- 高级C#消息机制(Advanced CSharp Messenger)
- Unity C# Advanced CSharp Messenger
- 通过C#使用Advanced CSharp Messenger
- Advanced CSharp Messenger
- Unity3D研究院之通过C#使用Advanced CSharp Messenger
- 通过C#使用Advanced CSharp Messenger(五十)
- Unity3D研究院之通过C#使用Advanced CSharp Messenger
- unity简单设计模式---Advanced CSharp Messenger
- Unity3D研究院之通过C#使用Advanced CSharp Messenger(五十)
- Unity3D研究院之通过C#使用Advanced CSharp Messenger(五十)
- Unity3D研究院之通过C#使用Advanced CSharp Messenger(五十)
- C#高级编程(第6版) Professional CSharp 2008
- C#消息机制
- C#消息机制
- C#消息处理机制
- c# 消息机制
- C#消息处理机制
- 关于linux 下用gcc 无法编译 bool 类型的问题解决
- C# 将字符串写入文件并打开该文件
- Noip2014 Day1 T2 联合权值
- Android studio编译第3方库libpng ,Box2D (CMake)
- java强制类型转换后调用方法加括号
- 高级C#消息机制(Advanced CSharp Messenger)
- Java 开发基于Zookeeper,Spring,vue.js的高并发多用户模块化微信商城系统(三) 构建高可用MySQL服务
- Laravel中Blade模板《一》——变量输出及控制流程
- 解决LoadRunner12录制时chrome卡死的情况
- 数据结构基础:栈(Stack)
- win关于修改命令行cmd/dos默认路径
- PHP之in_array()方法
- C# 静态方法使用
- [cvpr2017]Unsupervised Pixel–Level Domain Adaptation with Generative Adversarial Networks