我不确定以前是否有人问过这个问题,但我真的不知道如何寻找它,因为我不确定这个东西/我正在尝试做什么被称为什么......
我遇到的问题是,代码目前非常不DRY(有很多复制粘贴),我希望通过参数化使其更加通用,从而使其DRY起来。
我将发布相关代码 - 请注意,您不必详细了解代码及其执行的内容即可回答。
这是一个在后台执行操作的类:
现在,我有通用的信使类,可以有一个、两个、三个甚至没有参数 - 因此用户可以选择合适的事件处理程序来订阅事件。
这是不带通用参数的版本:
这是一个只需要一个参数的版本(我只需复制粘贴并添加一个 T):
作为你可能已经猜到的,接受两个参数的那个我只是复制粘贴了一遍,并添加了另一个通用类型,如
这是我试图消除的部分-但是我还不知道如何做到。 更准确地说,我正在寻找的是:仅一个
或者,(哪个都无所谓)
我在Unity3D中使用基于委托的通用消息系统 - 取自这里。
它的使用方式如下:
// Writing an event listener
void OnSpeedChanged(float speed)
{
this.speed = speed;
}
// Registering an event listener
void OnEnable()
{
Messenger<float>.AddListener("speed changed", OnSpeedChanged);
}
// Unregistering an event listener
void OnDisable()
{
Messenger<float>.RemoveListener("speed changed", OnSpeedChanged);
}
我遇到的问题是,代码目前非常不DRY(有很多复制粘贴),我希望通过参数化使其更加通用,从而使其DRY起来。
我将发布相关代码 - 请注意,您不必详细了解代码及其执行的内容即可回答。
这是一个在后台执行操作的类:
static internal class MessengerInternal
{
static public Dictionary<string, Delegate> eventTable = new Dictionary<string, Delegate>();
static public readonly MessengerMode DEFAULT_MODE = MessengerMode.REQUIRE_LISTENER;
static public void OnListenerAdding(string eventType, Delegate listenerBeingAdded)
{
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 (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, MessengerMode mode)
{
if (mode == MessengerMode.REQUIRE_LISTENER && !eventTable.ContainsKey(eventType)) {
throw new BroadcastException(string.Format("Broadcasting message {0} but no listener found.", eventType));
}
}
}
现在,我有通用的信使类,可以有一个、两个、三个甚至没有参数 - 因此用户可以选择合适的事件处理程序来订阅事件。
这是不带通用参数的版本:
// No parameters
static public class Messenger {
private static Dictionary<string, Delegate> eventTable = MessengerInternal.eventTable;
static public void AddListener(string eventType, Callback handler) {
MessengerInternal.OnListenerAdding(eventType, handler);
eventTable[eventType] = (Callback)eventTable[eventType] + handler;
}
static public void RemoveListener(string eventType, Callback handler) {
MessengerInternal.OnListenerRemoving(eventType, handler);
eventTable[eventType] = (Callback)eventTable[eventType] - handler;
MessengerInternal.OnListenerRemoved(eventType);
}
static public void Broadcast(string eventType) {
Broadcast(eventType, MessengerInternal.DEFAULT_MODE);
}
static public void Broadcast(string eventType, MessengerMode mode) {
MessengerInternal.OnBroadcasting(eventType, mode);
Delegate d;
if (eventTable.TryGetValue(eventType, out d)) {
Callback callback = d as Callback;
if (callback != null) {
callback();
} else {
throw MessengerInternal.CreateBroadcastSignatureException(eventType);
}
}
}
}
这是一个只需要一个参数的版本(我只需复制粘贴并添加一个 T):
// One parameter
static public class Messenger<T> {
private static Dictionary<string, Delegate> eventTable = MessengerInternal.eventTable;
static public void AddListener(string eventType, Callback<T> handler) {
MessengerInternal.OnListenerAdding(eventType, handler);
eventTable[eventType] = (Callback<T>)eventTable[eventType] + handler;
}
static public void RemoveListener(string eventType, Callback<T> handler) {
MessengerInternal.OnListenerRemoving(eventType, handler);
eventTable[eventType] = (Callback<T>)eventTable[eventType] - handler;
MessengerInternal.OnListenerRemoved(eventType);
}
static public void Broadcast(string eventType, T arg1) {
Broadcast(eventType, arg1, MessengerInternal.DEFAULT_MODE);
}
static public void Broadcast(string eventType, T arg1, MessengerMode mode) {
MessengerInternal.OnBroadcasting(eventType, mode);
Delegate d;
if (eventTable.TryGetValue(eventType, out d)) {
Callback<T> callback = d as Callback<T>;
if (callback != null) {
callback(arg1);
} else {
throw MessengerInternal.CreateBroadcastSignatureException(eventType);
}
}
}
}
作为你可能已经猜到的,接受两个参数的那个我只是复制粘贴了一遍,并添加了另一个通用类型,如
<T,U>
等。这是我试图消除的部分-但是我还不知道如何做到。 更准确地说,我正在寻找的是:仅一个
Messenger
类,但我仍然能够做到:Messenger<float>.Subscribe("player dead", OnDead);
Messenger<int, bool>.Subscribe("on something", OnSomething);
Messenger<bool, float, MyType>.Subscribe( stuff );
或者,(哪个都无所谓)
Messenger.Subscribe<float> ("player dead", OnDead);
你有个想法...
我该怎么做,怎样编写一个通用的通信程序,当我想添加另一个通用参数时,我不必复制粘贴并编写另一个完整版本,只因为我需要额外的参数?
非常感谢!