Je cherche un moyen d'autoriser une autre classe à ajouter des méthodes à mon délégué Action en invoquant une méthode de cette classe, plutôt qu'en appelant l'Action sur la première classe.
Voici ce dont j'ai besoin:
< pre> XXXCependant, lorsque j'appelle Execute (), rien ne se passe.
Comment puis-je le faire fonctionner?
4 Réponses :
Ce que vous voulez, c'est ceci:
class Program { static void Main(string[] args) { Action Execute = delegate { }; MetaAction meta = MetaAction.Create(h => Execute += h, h => Execute -= h); var prog = new ProgramTest(meta); var subscription = prog.AddMethod(); Execute(); subscription.Dispose(); } } public class MetaAction { public static MetaAction Create(Action<Action> attach, Action<Action> detach) => new MetaAction(attach, detach); public Action<Action> _attach; public Action<Action> _detach; private MetaAction(Action<Action> attach, Action<Action> detach) { _attach = attach; _detach = detach; } public IDisposable Subscribe(Action action) { _attach(action); return Disposable.Create(() => _detach(action)); } } public class ProgramTest { public MetaAction _meta; public ProgramTest(MetaAction meta) { _meta = meta; } public IDisposable AddMethod() { return _meta.Subscribe(Print); } public void Print() { Console.WriteLine("test"); Console.ReadLine(); } } public sealed class Disposable : IDisposable { public static IDisposable Create(Action action) => new Disposable(action); private readonly Action _action; private int _disposed; private Disposable(Action action) { _action = action; } public void Dispose() { if (Interlocked.Exchange(ref _disposed, 1) == 0) { _action(); } } }
Cela imprime test
sur la console.
Il s'agit d'une version légèrement meilleure de ce modèle:
class Program { static void Main(string[] args) { Action Execute = delegate { }; ProgramTest prog = new ProgramTest(h => Execute += h, h => Execute -= h); var subscription = prog.AddMethod(); Execute(); subscription.Dispose(); } } class ProgramTest { public Action<Action> _attach; public Action<Action> _detach; public ProgramTest(Action<Action> attach, Action<Action> detach) { _attach = attach; _detach = detach; } public IDisposable AddMethod() { _attach(Print); return Disposable.Create(() => _detach(Print)); } public void Print() { Console.WriteLine("test"); Console.ReadLine(); } } public sealed class Disposable : IDisposable { public static IDisposable Create(Action action) => new Disposable(action); private readonly Action _action; private int _disposed; private Disposable(Action action) { _action = action; } public void Dispose() { if (Interlocked.Exchange(ref _disposed, 1) == 0) { _action(); } } }
J'irais même plus loin et définirais une MetaAction
- vous pouvez transmettre autant que vous aimez et ajoutez-y des méthodes.
class Program { static void Main(string[] args) { Action Execute = delegate { }; ProgramTest prog = new ProgramTest(h => Execute += h); prog.AddMethod(); Execute(); } } class ProgramTest { public Action<Action> execute; public ProgramTest(Action<Action> action) { execute = action; } public void AddMethod() { execute(Print); } public void Print() { Console.WriteLine("test"); Console.ReadLine(); } }
Ça a marché! Merci! Mais comment puis-je supprimer et ajouter de nouveaux appels de méthode au délégué Action?
@JohnnyB - Vous ne pouvez pas. Faire h => Execute + = h, h => Execute - = h
est la seule façon que cela fonctionne.
Une autre option consiste à placer le délégué (immuable) dans un conteneur mutable.
public class ActionContainer { public Action Action { get; set; } = () => { }; } class Program { static void Main(string[] args) { ActionContainer execute = new ActionContainer(); ProgramTest prog = new ProgramTest(execute); prog.AddMethod(); execute.Action(); } } class ProgramTest { public ActionContainer execute; public ProgramTest(ActionContainer action) { execute = action; } public void AddMethod() { execute.Action += Print; } public void Print() { Console.WriteLine("test"); Console.ReadLine(); } }
Génial, très simple et fait le travail. Me permet de jouer avec le délégué Action n'importe où. Merci!
Votre Programme
peut exposer un événement auquel votre autre classe peut enregistrer un autre gestionnaire:
class Program { public static event Action MyEvent; static void Main(string[] args) { ProgramTest prog = new ProgramTest(); prog.AddMethod(); // raise the event and invoke the registered handlers MyEvent?.Invoke(); } } class ProgramTest { private Action handler; public ProgramTest() { handler = Print; } public void AddMethod() { Program.MyEvent += handler; // regsiter the execute-delegate to the event // or directly: Program.MyEvent += Print; } public void Print() { Console.WriteLine("test"); Console.ReadLine(); } }
J'ai l'impression que vous ne l'avez peut-être pas testé avant de poster.
Vous pouvez le faire fonctionner en appelant prog.Execute au lieu de Execute, tout comme le code ci-dessous.
class Program { static void Main(string[] args) { Action Execute = delegate { }; ProgramTest prog = new ProgramTest(ref Execute); Execute += prog.Print; prog.AddMethod(); Execute(); } }
ou vous devez attribuer la méthode Print à la méthode principale Exécuter le délégué comme ci-dessous
class Program { static void Main(string[] args) { Action Execute = delegate { }; ProgramTest prog = new ProgramTest(ref Execute); prog.AddMethod(); prog.execute(); } }
Merci pour votre réponse. Mais j'ai plusieurs classes différentes qui ajouteront des méthodes à ce délégué. La classe principale elle-même ne sait pas quand cela se produira et quels objets le feront.
Vous ne pouvez pas - pas comme ça. Les délégués sont des types immuables - le
+ =
crée un nouveau délégué. Le fait que vous passiezref Action action
ne fait rien, car le champexecute
n'est pasref
(et ne peut pas non plus l'être)