Не съм сигурен дали това е задавано преди, но наистина не знаех как да го търся, тъй като не съм сигурен как точно се нарича това нещо / това, което се опитвам да направя...
Имам генерична система за съобщения, базирана на делегати, която използвам в 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);
}
Проблемът, който имам, е, че кодът в момента е много несух (има много copy paste) и искам да го изсуша, като се надявам да го параметризирам, правейки го по-генеричен.
Ще публикувам съответния код - Моля, имайте предвид, че всъщност не е нужно да разбирате кода в детайли и какво прави, за да отговорите.
Ето един клас, който прави неща зад сцената:
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);
Схванахте идеята...
Как мога да направя това, как мога да напиша общ месинджър, така че когато искам да добавя още един общ аргумент, да не трябва да копирам-поставям и да пиша цяла друга версия, просто защото имах нужда от допълнителен аргумент?
Благодаря много!
Има точка и запетая точно след цикъла while
което го прави безкраен цикъл, защото представлява празна инструкция, точно като
така че всъщност никога не влизате
блок и код след него, което означава, че не пишете нищо във вашия файл с резултати и дори не го затваряте. Всичко, което имате, ако е създаден празен файл с
Така че премахнете тази точка и запетая.
Между другото можете лесно да забележите този вид грешки, ако оставите кода на вашия IDE формат вместо вас. Eclipse форматира вашия пример за мен като
което, както виждате, показва доста добре, че вашият цикъл всъщност изпълнява празен оператор вместо кодов блок.
- person vexe   schedule 06.11.2013The two languages are similar
- Да, през 2001 г. беше вярно. Но сега сме 2013 г. C# порасна. java няма. виждането на java код кара един C# разработчик да повърне през 2013 г. Много повече, ако наистина е C# код, написан от java програмист. - person Federico Berasategui   schedule 06.11.2013Messenger
изпълнението на MVVM Light, по-голямата част от кода е независим от UI/платформа. Базирам се само на неща катоAction<T>
иWeakReference
, които са дефинирани вmscorlib
и не зависят от рамката на потребителския интерфейс или подобни неща. Можете да използвате технитеMessenger
и да премахнете специфичните за WPF части, катоDialogMessage
и други подобни. - person Federico Berasategui   schedule 06.11.2013Make your methods generic
- КатоBroadcast<T>, Broadcast<T, U>, Broadcast<T, etc>
? същия проблем. Или имахте предвид нещо друго? (Между другото, не смятате, че преоткривате колелото, ако правите телевизор, за да научите как се прави. Но смятате, че го правите, за да гледате телевизия) - person vexe   schedule 06.11.2013Otherwise, good luck reinventing the wheel. see ya
това отношение....... - Не съм сигурен дали не искате да помогнете или не можете. Имам прост (трябва да има) проблем и искам да знам как да го разреша. Не искам вече направени неща. Искам да се науча. Ако можете да помогнете за разрешаването на проблема, ще го оценявам, ако не можете/не искате, просто защото кодът изглежда отвратително, тогава наистина мисля, че не трябва да приемаме тези коментари всяка друга причина става дълга и извън темата. Благодаря. - person vexe   schedule 06.11.2013