Reputation: 41
I am looking for a way to allow another class add methods to my Action delegate by invoking a method from that class, than calling the Action on the first class.
This is what I need:
class Program
{
static void Main(string[] args)
{
Action Execute = delegate { };
ProgramTest prog = new ProgramTest(ref Execute);
prog.AddMethod();
Execute();
}
}
class ProgramTest
{
public Action execute;
public ProgramTest(ref Action action)
{
execute = action;
}
public void AddMethod()
{
execute += Print;
}
public void Print()
{
Console.WriteLine("test");
Console.ReadLine();
}
}
However, when I call Execute(), nothing happens.
How can I make it work?
Upvotes: 1
Views: 1954
Reputation: 37123
Your Program
may expose an event to which your other class may register another handler:
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();
}
}
Upvotes: -1
Reputation: 61
You can make it work by make a call to prog.Execute instead of Execute, just like below code.
class Program
{
static void Main(string[] args)
{
Action Execute = delegate { };
ProgramTest prog = new ProgramTest(ref Execute);
prog.AddMethod();
prog.execute();
}
}
or you need to assign Print method to main method Execute delegate like below
class Program
{
static void Main(string[] args)
{
Action Execute = delegate { };
ProgramTest prog = new ProgramTest(ref Execute);
Execute += prog.Print;
prog.AddMethod();
Execute();
}
}
Upvotes: 0
Reputation: 117175
What you want is this:
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();
}
}
That prints test
to the console.
This is a slightly better version of this pattern:
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();
}
}
}
I'd even go one step further and define a MetaAction
- you can pass this around as much as you like and add methods to it.
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();
}
}
}
Upvotes: 1
Reputation: 42350
Another option is to put the (immutable) delegate inside a mutable container.
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();
}
}
Upvotes: 1