2015-04-29 2 views
1

Je recherche la manière appropriée et élégante de créer une architecture Mediator/Subscriber avec des rappels typés.Passer des délégués en tant que paramètres pour le modèle médiateur/abonné

Supposons que j'ai une classe-à-dire les délégués des «événements de:

public class E 
{ 
    public delegate void SomethingHappened (float a, int b); 
    public delegate void ProgressFinished (int[] c); 
} 

Maintenant, je veux créer une classe de médiateur qui enregistrerait callbacks aux délégués et callbacks d'expédition avec les paramètres fournis:

public class Mediator 
{ 
    public static void Register (???, Action callback) 
    { 
     // supplied delegate += callback 
    } 

    public static void Dispatch (???, params object[] list) 
    { 
     // executing supplied delegate with params: delegate(list) 
    } 
} 

donc je pourrais l'utiliser de la manière suivante:

// Class A: 
Mediator.Register (E.SomethingHappened, OnSomethingHappened); 
private void OnSomethingHappened (float a, int b) 
{ 
    //.......... 
} 

// Class B: 
Mediator.Dispatch (E.SomethingHappened, 0.1f, 'qwe'); 

maintenant t Le problème est que je ne peux pas passer le délégué en tant que paramètre pour enregistrer ou envoyer. Comment puis-je résoudre ce problème?

+1

Je pense que vous avez mal compris les délégués. Un délégué * est * un rappel (ou peut être utilisé comme tel) - vous n'enregistrez pas un rappel * avec * un délégué. Peut-être cherchez-vous plutôt des événements? –

+1

J'ai modifié votre titre. S'il vous plaît voir, "[Les questions devraient inclure" tags "dans leurs titres?] (Http://meta.stackexchange.com/questions/19190/)", où le consensus est "non, ils ne devraient pas". –

+1

@JonSkeet: Je crois que OP voulait enregistrer une méthode de rappel concrète basée sur son type de délégué, mais ne savait pas comment passer le type de délégué à la méthode – Groo

Répondre

1

Vous devez adopter une approche différente: laissez vos expéditeurs envoyer les messages et demandez à votre médiateur de les envoyer à différents gestionnaires en fonction de leur type.

génériques En utilisant, ce serait refondus à:

// handlers should be differentiated by message type 
public class SomethingHappenedMessage 
{ 
    public float A { get; set; } 
    public int B { get; set; } 
} 

public class Mediator 
{ 
    private readonly Dictionary<Type, object> _dict = new Dictionary<Type, object>(); 

    public void Register<Tmessage>(Action<Tmessage> callback) 
    { 
     _dict[typeof(Tmessage)] = callback; 
    } 

    public void Dispatch<Tmessage>(Tmessage msg) 
    { 
     var handler = _dict[typeof(Tmessage)] as Action<Tmessage>; 
     handler(msg); 
    } 
} 

Ou, vous pourriez avoir plusieurs gestionnaires pour chaque type de message:

public class Mediator 
{ 
    readonly Dictionary<Type, List<object>> _handlersByType = new Dictionary<Type, List<object>>(); 

    public void Register<Tmessage>(Action<Tmessage> callback) 
    { 
     List<object> handlers; 
     if (!_handlersByType.TryGetValue(typeof(Tmessage), out handlers)) 
      _handlersByType[typeof(Tmessage)] = handlers = new List<object>(); 

     handlers.Add(callback); 
    } 

    public void Dispatch<Tmessage>(Tmessage msg) 
    { 
     List<object> handlers; 
     if (!_handlersByType.TryGetValue(typeof(Tmessage), out handlers)) 
      return; 

     foreach (Action<Tmessage> handler in handlers) 
      handler(msg); 
    } 
} 
+0

Merci, ça a l'air plutôt bien. On dirait que je ne peux pas réduire la déclaration de Tmessage plus loin? –

+0

@VincentPride: Je suppose qu'il pourrait y avoir un moyen de disséquer un type de délégué en utilisant la réflexion, mais c'est de loin l'approche la plus propre. Vous pouvez déclarer n'importe quelle classe de message, n'importe où, et enregistrer son gestionnaire ici. En outre, pour un couplage plus lâche, notez que j'ai fait toutes les méthodes instance (vs vos static) afin que vous puissiez passer le médiateur. – Groo