c# delegates and events - c#

im trying to learn delegates and events in c#, i understand that an event is some sort of a wrapper for a delegate and a delegate is a pointer for functions/methods...
below is my code but when i run it, nothing is being shown... what could be the problems?
public class ClassHandler
{
public delegate void DoProcesses();
public event DoProcesses DoProcessesEvent;
}
public class Class1
{
public void Func1()
{
Console.WriteLine("Class 1 doing function 1");
}
public void Func2()
{
Console.WriteLine("Class 1 doing function 2");
}
}
public class Class2
{
public void Func1()
{
Console.WriteLine("Class 2 doing function 1");
}
public void Func2()
{
Console.WriteLine("Class 2 doing function 2");
}
}
class Program
{
static void Main(string[] args)
{
Class1 cs1 = new Class1();
Class2 cs2 = new Class2();
ClassHandler main = new ClassHandler();
main.DoProcessesEvent += new ClassHandler.DoProcesses(cs1.Func1);
main.DoProcessesEvent += new ClassHandler.DoProcesses(cs1.Func2);
main.DoProcessesEvent += new ClassHandler.DoProcesses(cs2.Func1);
main.DoProcessesEvent += new ClassHandler.DoProcesses(cs2.Func2);
main.DoProcessesEvent += new ClassHandler.DoProcesses(ff); // this line here is causing an error: An object reference is required for the non-static field, method, or property 'TryDelegatesAndEvents.Program.ff()'
Console.Read();
}
public void ff()
{
Console.WriteLine("gggg");
}
}
UPDATE: how do i raise the event so it will execute the methods already?

Problem with this line: main.DoProcessesEvent += new ClassHandler.DoProcesses(ff)
That is because your method ff() is a non-static method and you can't access it directly like that from a static method.
Make your method ff as static, or create and object of the containing class and assign the method with an instance of it.
For Comments: The reason you are not seeing anything is because you are just binding them to an event DoProcessesEvent, but you are not raising the event any where. You are only defining the handler for the event.
EDIT:
Change your ClassHandler class to:
public class ClassHandler
{
public delegate void DoProcesses();
public event DoProcesses DoProcessesEvent;
public void OnDoProcessEvent()
{
if (DoProcessesEvent != null)
DoProcessesEvent();
}
}
In your Main method before Console.Read(); Type:
main.OnDoProcessEvent();
This will raise the event and it will handled from the application and will give you the following output.
Class 1 doing function 1
Class 1 doing function 2
Class 2 doing function 1
Class 2 doing function 2
gggg

change main.DoProcessesEvent += new ClassHandler.DoProcesses(ff); to main.DoProcessesEvent += new ClassHandler.DoProcesses(new Program().ff); or make ff static

Well it does not compile due to the line:
main.DoProcessesEvent += new ClassHandler.DoProcesses(ff);
The error VS spits out is that:
An object reference is required for the non-static field, method, or property 'ConsoleApplication2.Program.ff()'
Just change your ff() method to be static to get around it.
Eg:
public static void ff()
{
Console.WriteLine("gggg");
}

Besides the problem pointed out in earlier comments, You have to trigger the event.
make a copy of an event before you check it for null and fire it. This will eliminate a potential problem with threading where the event becomes null at the location right between where you check for null and where you fire the event:
// Copy the event delegate before checking/calling
EventHandler copy = DoProcessesEvent ;
if (copy != null)
copy(this, EventArgs.Empty); // Call any handlers on the copied list
This will ensure that your event fires and you will get the result.

Just to add to #Habib's answer, it would be fairly unusual to subscribe instance class methods as event handlers of an object potentially in another scope (e.g. what happens if Class1 goes out of scope, yet main() still has a subscription?). A more common scenario would be to subscribe (and de-subscribe) handlers in the same scope, often in an asynchronous manner (the below events are still raised synchronously).
namespace ConsoleApplication1
{
public delegate void ProcessCompletedEvent(string description);
public class Class1
{
public void Func1()
{
// Do Func1 work
Thread.Sleep(500);
RaiseEvent("Func1 completed");
}
public void Func2()
{
// Do Func2 work
Thread.Sleep(1000);
RaiseEvent("Func2 completed");
}
private void RaiseEvent(string description)
{
if (ProcessCompleted != null)
{
ProcessCompleted(description);
}
}
public event ProcessCompletedEvent ProcessCompleted;
}
class Program
{
static void Main(string[] args)
{
Class1 cs1 = new Class1();
// Wire up event handler
cs1.ProcessCompleted += new ProcessCompletedEvent(MyHandler);
cs1.Func1();
cs1.Func2();
Console.Read();
// Remove the subscription
cs1.ProcessCompleted -= MyHandler;
}
// *** Is in the same scope as main, which subscribes / desubscribes
public static void MyHandler(string description)
{
Console.WriteLine(description);
}
}
}

Related

initialize event actions to raise event notifications

I would like to create event actions to notify other classes when something happened. So my current flow looks like this
For testing purposes I created this code
Program.cs
Instantiate the first class and call a method from it (constructor is fine).
internal class Program
{
private static void Main(string[] args)
{
First f = new First();
}
}
First.cs
Instantiate the second class and call a method from it (constructor is fine). Listen for an event of the second class when some data has changed.
internal class First
{
public First()
{
// ...
Second s = new Second();
s.Updated += OnSecondUpdated;
}
private void OnSecondUpdated()
{
Console.WriteLine("Done");
Console.ReadLine();
}
}
Second.cs
Instantiate the third class and call a method from it (constructor is fine). Listen for an event of the third class when some data has changed and raise the own one.
internal class Second
{
public event Action Updated;
public Second()
{
// ...
Third t = new Third();
t.Updated += OnThirdUpdated;
}
private void OnThirdUpdated()
{
// ...
Updated();
}
}
Third.cs
Raise an event when some data has changed.
internal class Third
{
public event Action Updated;
public Third()
{
// ...
Updated();
}
}
Unfortunately the event variables are null. How can I instantiate these variables properly?
The problem here is that you're trying to do this in the constructor, where at that time nothing has (yet) been assigned to the Updated event. You can "solve" this by checking for null:
internal class Third
{
public event Action Updated;
public Third()
{
// ...
if(Updated != null)
Updated();
}
}
But it wont mean your code now "works" as you only assign the event a handler after constructor has been called:
Third t = new Third();
t.Updated += OnThirdUpdated;
So one possible solution for this pattern is to NOT do this raising of the event in the constructor, and instead defer the logic to another method.
internal class Third
{
public event Action Updated;
public Third()
{
}
public void Init()
{
// ...
if(Updated != null)
Updated();
}
}
Third t = new Third();
t.Updated += OnThirdUpdated;
t.Init();
You call the Update() before the classes can subscribe to the events, due to the constructor of the underlying object being called first. I changed it so that the constructor takes the related class and subscribes the event itself.
internal class First
{
public First()
{
Second s = new Second(this);
}
internal void OnSecondUpdated()
{
Console.WriteLine("Done");
Console.ReadLine();
}
}
internal class Second
{
public event Action Updated;
public Second(First f)
{
Updated += f.OnSecondUpdated;
Third t = new Third(this);
}
internal void OnThirdUpdated()
{
Updated();
}
}
internal class Third
{
public event Action Updated;
public Third(Second s)
{
Updated += s.OnThirdUpdated;
Updated();
}
}

How to pass event to another event

I want pass event to another event,now I use function to do that.
Can C# pass event like b.WriteEvent += a.WriteEvent ?
If I had a lot class,and just want pass argument to above class.
I want write like : a.event += b.event. b.event += c.event
Instead of a lot no use method.
Thanks.
class Program
{
static void Main(string[] args)
{
ClassA a = new ClassA();
ClassB b = new ClassB();
a.WriteEvent += MainWrite;
b.WriteEvent += a.WireFunction; // Now I use
//b.WriteEvent += a.WriteEvent; <= Can I use like this ?
b.WireFunction("some str");
Console.ReadLine();
}
static void MainWrite(string str)
{
Console.WriteLine(str);
}
}
class ClassA
{
public event Handler WriteEvent;
public void WireFunction(string str)
{
WriteEvent(str);
}
}
class ClassB
{
public event Handler WriteEvent;
public void WireFunction(string str)
{
WriteEvent(str);
}
}
public delegate void Handler(string str);
Fact:You cannot provide an event that subscribes to an event.
All delegates (events, actions or funcs) ar multicast delegates in C#.
That means you can subscribe to an event multiple times.
In order to subscribe to an event you have to provide an action or a function. (I use the term function instead of method because we may provide a lambda)
What follows is snipped that subscribes all subscribers of Event1 to Event2.
I believe this is what you intend to do.
public class SomeClass
{
public event EventHandler Event1;
public event EventHandler Event2;
public SomeClass()
{
Event1 += Subscriber1;
Event1 += Subscriber2;
var subscribers = Event1.GetInvocationList();
if(subscribers != null)
{
foreach(var subscriber in subscribers)
{
EventHandler realSubscriber = (EventHandler)subscriber;
Event2 += realSubscriber;
}
}
Event1(this, EventArgs.Empty);
Event2(this, EventArgs.Empty);
}
public void Subscriber1(object sender, EventArgs e)
{
Console.WriteLine("Subscriber 1 invoked");
}
public void Subscriber2(object sender, EventArgs e)
{
Console.WriteLine("Subscriber 2 invoked");
}
}
Creating an instance of the SomeClass will print:
Subscriber 1 invoked
Subscriber 2 invoked
Subscriber 1 invoked
Subscriber 2 invoked
EDIT:
I tried to move the logic to an extension method and also to a normal utility method. Both did not work very well because events are null when they have no subscribers. Passing an event without subscribers would then result in the same behaviour as if null was passed. For now, this is the best I could come up with.

Event handler not firing when its caller was invoked in the delegate of a previous event

tl;dr
Implementing Class:
public Main()
{
Foo foo = new Foo();
foo.OnBarOneResponse += foo_OnBarOneResponse;
foo.OnBarTwoResponse += foo_OnBarTwoResponse;
foo.FetchBarOne();
}
void foo_OnBarOneResponse(String response)
{
// Called successfully.
this.foo.FetchBarTwo();
}
void foo_OnBarTwoResponse(String response)
{
// Never called :(
}
Foo.cs
private MyJavascriptInjector _javascriptInjector = new MyJavascriptInjector();
public delegate void OnBarOneResponseHandler(String response);
public delegate void OnBarTwoResponseHandler(String response);
public event OnBarOneResponseHandler OnBarOneResponse = delegate { };
public event OnBarTwoResponseHandler OnBarTwoResponse = delegate { };
private void _onBarOneResponse(String response)
{
// Called Successfully
OnBarOneResponse(response);
}
private void _onBarTwoResponse(String response)
{
// Never called :(
OnBarTwoResponse(response);
}
public Foo()
{
webBrowser.ObjectForScripting = _javascriptInjector;
_javascriptInjector.OnBarOneResponse += _onBarOneResponse;
_javascriptInjector.OnBarTwoResponse += _onBarTwoResponse;
webBrowser.Navigate("http://myurl", null, new Byte[0], myHeaders");
}
public void FetchBarOne()
{
webBrowser.InvokeScript("fetchBarOne");
}
public void FetchBarTwo()
{
webBrowser.InvokeScript("fetchBarTwo");
}
MyJavascriptInjector.cs
[System.Runtime.InteropServices.ComVisible(true)]
public class MyJavascriptInjector
{
public delegate void OnBarOneResponseHandler(string response);
public delegate void OnBarTwoResponseHandler(string response);
public event OnBarOneResponseHandler OnBarOneResponse;
public event OnBarTwoResponseHandler OnBarTwoResponse;
public void OnBarOneResponse(String response)
{
// Called successfully!
OnBarOneResponse(response);
}
public void OnBarTwoResponse(String response)
{
// ALSO CALLED SUCCESSFULLY BUT WHEN CALLING THIS Foo.cs event NEVER GETS FIRED.
// IT GETS LOST SOMEWHERE BETWEEN HERE and Foo.cs!
OnBarTwoResponse(response);
}
}
=================
I have an object Foo that has two methods on it, FetchBarOne and FetchBarTwo.
Each method has an event on it, OnBarOneResponse and OnBarTwoResponse.
The implementing class registers Foo's events in its constructor using the notation "+=" and defines a callback function for each: foo_OnBarOneResponse(String response) and foo_OnBarTwoResponse(String response).
PROBLEM:
The implementing class observes the following:
Calls this.foo.FetchBarOne();
foo_OnBarOneResponse(String response) is fired at a later time.
In this callback, implementing class immediately calls this.foo.FetchBarTwo();
foo_OnBarTwoResponse(String response) never fires.
MORE INFORMATION:
Foo has wrapped WebBrowser and is calling InvokeScript to execute javascript in the loaded webpage. This webpage has many javascript functions on it, including FetchBarOne and FetchBarTwo on it. When debugging, FetchBarTwo is called and it successfully responds with data. However, after WebBrowser returns the data successfully, when Foo calls its internal OnBarTwoResponseHandler event delegate that was registered by the implementing class, it gets "lost" somewhere in between - even though it is not null at it clearly has a reference to it.
FAILED ATTEMPTS OF FIXING ISSUE
Implementing class tried using Dispatcher.Invoke(DispatcherPriority.Normal, new ThreadStart(() => this.foo.FetchBarTwo())); to try and call it from the UI thread. No success.
If anyone has any thoughts on this matter, I would be most grateful. Thanks!
The this.foo field is NOT the same instance as the foo variable.
From your example:
public Main()
{
Foo foo = new Foo();
foo.OnBarOneResponse += foo_OnBarOneResponse;
foo.OnBarTwoResponse += foo_OnBarTwoResponse;
foo.FetchBarOne();
}
void foo_OnBarOneResponse(String response)
{
// Called successfully.
this.foo.FetchBarTwo();
}
Try using your field (which was not included in your example):
private Foo foo;
public Main()
{
this.foo = new Foo();
this.foo.OnBarOneResponse += foo_OnBarOneResponse;
this.foo.OnBarTwoResponse += foo_OnBarTwoResponse;
this.foo.FetchBarOne();
}

Why use events for what I can do with Delegates?

I know Events are always associated with Delegates. But, I am missing some core use of Events, and trying to understand that.
I created a simple Event program, as below, and it works perfectly fine.
namespace CompleteRef3._0
{
delegate void someEventDelegate();
class EventTester
{
public event someEventDelegate someEvent;
public void doEvent()
{
if (someEvent != null) someEvent();
}
}
class Program
{
static void EventHandler1()
{
Console.WriteLine("Event handler 1 called..");
}
static void EventHandler2()
{
Console.WriteLine("Event handler 2 called..");
}
static void EventHandler3()
{
Console.WriteLine("Event handler 3 called..");
}
static void Main(string[] args)
{
EventTester evt = new EventTester();
evt.someEvent += EventHandler1;
evt.someEvent += EventHandler2;
evt.someEvent += EventHandler3;
evt.doEvent();
Console.ReadKey();
}
}
}
I replaced the event declaration with delegates. That is I replaced the line public event someEventDelegate someEvent; with someEventDelegate someEvent; on the above program, and I still get the same result. Now, I was confused why we need to use Events, if it can be achieved by Delegates only. What is the real use of Events?
The modified program without events is as below -
namespace CompleteRef3._0
{
delegate void someEventDelegate();
class EventTester
{
someEventDelegate someEvent;
public void doEvent()
{
if (someEvent != null) someEvent();
}
}
class Program
{
static void EventHandler1()
{
Console.WriteLine("Event handler 1 called..");
}
static void EventHandler2()
{
Console.WriteLine("Event handler 2 called..");
}
static void EventHandler3()
{
Console.WriteLine("Event handler 3 called..");
}
static void Main(string[] args)
{
EventTester evt = new EventTester();
evt.someEvent += EventHandler1;
evt.someEvent += EventHandler2;
evt.someEvent += EventHandler3;
evt.doEvent();
Console.ReadKey();
}
}
}
Imagine you have 3 subscribers who are interested in your someEvent. Let's further imagine they are interested in receiving events from the same EventTester instance. For brevity, let's leave out the details of how the exact same instance is passed to all the clients. When I say clients, I mean any class who is a subscriber to the event.
Here is the instance:
EventTester evt = new EventTester();
They have subscribed to the event of the above instance as shown below:
Client 1
evt.someEvent += Client1Handler1;
evt.someEvent += Client1Handler2;
Client 2
evt.someEvent += Client2Handler1;
Client 3
evt.someEvent += Client3Handler1;
evt.someEvent += Client3Handler2;
Client 4:
Imagine client 4 did one of the 3 below:
// 1: See Note 1 below
evt.someEvent = null;
// 2: See Note 2 below
evt.someEvent = new someEventDelegate(MyHandler);
// 3: See Note 3 below
evt.someEvent();
//...
private void MyHandler()
{
MessageBox.Show("Client 4");
}
Note 1
Client 1, 2, and 3 will not be getting any events anymore. Why? Because Client 4 just did this evt.someEvent = null; and in EventTester you have this line of code:
if (someEvent != null) someEvent();
Since that condition will not pass anymore, no event will be raised. There is nothing wrong with the above line of code by the way. But there is the problem with using delegates: It can be assigned to.
Note 2
It has been completely over-written to a brand new instance. Now regardless of the client, they will all see a message box that says "Client 4".
Note 3
Ooops all of a sudden one of the clients is broadcasting the event.
Imagine for a second EventTester was a Button and someEvent was Click. Imagine you had multiple clients interested in the click event of this button. All of a sudden, one client decides no-one else should get notifications (Note 1). Or one client decides that when the button is clicked, it will be handled only 1 way (Note 2). Or it has made the decision that it will decide when a button is clicked even though the button may not have been clicked (Note 3).
If you have an event and one of the clients tried the above, they will not be allowed and get a compile error, like this:
Sure, you can use delegates because behind the scenes an event is a construct that wraps a delegate.
But the rationale of using events instead of delegates is the the same as for using properties instead of fields - data encapsulation. It's bad practice to expose fields (whatever they are - primitive fields or delegates) directly.
By the way, you missed a public keyword before your delegate field to make it possible in the second snippet.
Another "by the way" with the second snippet: for delegates you should use Delegate.Combine instead of "+=".
The main purpose of events is to prevent subscribers from interfering with each other. If you do not use events, you can:
Replace other subscribers by reassigning delegate(instead of using the += operator),
Clear all subscribers (by setting delegate to null),
Broadcast to other subscribers by invoking the delegate.
Source: C# in a Nutshell
public class Program
{
public static void Main()
{
Number myNumber = new Number(100000);
myNumber.PrintMoney();
myNumber.PrintNumber();
Console.ReadKey();
}
}
public class Number
{
private PrintHelper _printHelper;
public Number(int val)
{
_value = val;
_printHelper = new PrintHelper();
//subscribe to beforePrintEvent event
_printHelper.beforePrintEvent += printHelper_beforePrintEvent;
}
//beforePrintevent handler
void printHelper_beforePrintEvent(string message)
{
Console.WriteLine("BeforePrintEvent fires from {0}", message);
}
private int _value;
public int Value
{
get { return _value; }
set { _value = value; }
}
public void PrintMoney()
{
_printHelper.PrintMoney(_value);
}
public void PrintNumber()
{
_printHelper.PrintNumber(_value);
}
}
public class PrintHelper
{
public delegate void BeforePrintDelegate(string message);
public event BeforePrintDelegate beforePrintEvent;
public PrintHelper()
{
}
public void PrintNumber(int num)
{
if (beforePrintEvent != null)
beforePrintEvent.Invoke("PrintNumber");
Console.WriteLine("Number: {0,-12:N0}", num);
}
public void PrintDecimal(int dec)
{
if (beforePrintEvent != null)
beforePrintEvent("PrintDecimal");
Console.WriteLine("Decimal: {0:G}", dec);
}
public void PrintMoney(int money)
{
if (beforePrintEvent != null)
beforePrintEvent("PrintMoney");
Console.WriteLine("Money: {0:C}", money);
}
public void PrintTemperature(int num)
{
if (beforePrintEvent != null)
beforePrintEvent("PrintTemerature");
Console.WriteLine("Temperature: {0,4:N1} F", num);
}
public void PrintHexadecimal(int dec)
{
if (beforePrintEvent != null)
beforePrintEvent("PrintHexadecimal");
Console.WriteLine("Hexadecimal: {0:X}", dec);
}
}

How to pass an event to a method?

I would like to create a method that takes an event as an argument and adds eventHandler to it to handle it properly. Like this:
I have two events:
public event EventHandler Click;
public event EventHandler Click2;
Now I would like to pass a particular event to my method like this (pseudocode):
public AttachToHandleEvent(EventHandler MyEvent)
{
MyEvent += Item_Click;
}
private void Item_Click(object sender, EventArgs e)
{
MessageBox.Show("lalala");
}
ToolStripMenuItem tool = new ToolStripMenuItem();
AttachToHandleEvent(tool.Click);
Is it possible?
I've noticed that this code worked fine, and returned to my project and noticed that when I pass an event declared in my class, it works, but when I pass event from other class it still does not work.
What I get is this error:
The event
'System.Windows.Forms.ToolStripItem.Click'
can only appear on the left hand side
of += or -=
My original answer was suitable from within the class that defined the event, but you've since updated your question to reflect that you wish to accomplish this from outside the defining class, so I've stricken that.
Only the class that defines an event can refer to the implicit delegate variable that the event uses. From outside that class, you only have access to the add and remove methods, via += and -=. This means that you can't do what you're asking, directly. You can, however, use a functional approach.
class A{
public event EventHandler Event1;
public void TriggerEvent1(){
if(Event1 != null)
Event1(this, EventArgs.Empty);
}
}
class B{
static void HandleEvent(object o, EventArgs e){
Console.WriteLine("Woo-hoo!");
}
static void AttachToEvent(Action<EventHandler> attach){
attach(HandleEvent);
}
static void Main(){
A a = new A();
AttachToEvent(handler=>a.Event1 += handler);
a.TriggerEvent1();
}
}
I did it like this:
public AttachToHandleEvent(Object obj, string EventName)
{
EventInfo mfi = obj.GetType().GetEvent(EventName);
MethodInfo mobj = mfi.GetAddMethod();
mobj.Invoke(obj, new object[] { Item_Click});
}
private void Item_Click(object sender, EventArgs e)
{
MessageBox.Show("lalala");
}
ToolStripMenuItem tool = new ToolStripMenuItem();
AttachToHandleEvent(tool "Click");
Thank you all for advice. This solution could not be done without your help.
It's not possible. You can use a delegate instead of an event if that meets your needs.
Just write tool.Click += Item_Click;
Edit: From MSDN "Events can only be invoked from within the class or struct where they (it) are declared". So what you are trying to do is not possible. Could you elaborate more on your needs? Why would you want to pass an event as a parameter?
delegate void doIt(object sender, object data);
event doIt OnDoIt;
void add(doIt theDel)
{
OnDoIt += theDel;
}
void doIt1(object a, object b)
{
}
void doIt2(object a, object b)
{
}
void add()
{
add(doIt1);
add(doIt2);
}
Your question suggests that you got some mechanisms wrong:
You can't pass events!
You most probably want to pass a function as a parameter, so the calling method will call that other method at some point. In technical terms this is a delegate. I suggest using the already defined Action class. Here's an example snippet:
void MyFunction (string otherArguments, Action onFinished){
...
if (onFinished != null)
onFinished.Invoke();
}
The nice thing about this is that when calling MyFunction you can declare the Action using the inline syntax:
MyFunction("my other argument", ()=>{
///do stuff here, which will be execuded when the action is invoked
});
I pass functions/methods (instead of events) like this:
class A
{
public void something()
{
var myAction =
new Action<object, object>((sender, evArgs) => {
MessageBox.Show("hiii, event happens " + (evArgs as as System.Timers.ElapsedEventArgs).SignalTime);
});
B.timer(myAction);
}
}
class B
{
public static void timer( Action<object, System.Timers.ElapsedEventArgs> anyMethod)
{
System.Timers.Timer myTimer = new System.Timers.Timer();
myTimer.Elapsed += new System.Timers.ElapsedEventHandler(anyMethod);
myTimer.Interval = 2000;
myTimer.Start();
}
}
Giving an update to this question with an object oriented solution.
Instead of using an Action<EventHandler> that registers the event, you could create an object handling that for you
public class AEvent
{
private readonly A aInstance;
private AEvent(A instance) {
aInstance = instance;
}
public void Add(EventHandler eventHandler)
=> a.Event1 += eventHandler;
public void Remove(EventHandler eventHandler)
=> a.Event1 -= eventHandler;
public EventHandler Invoke => aInstance.Event1;
}
Then later on use that object like this:
static void Main(){
A a = new A();
AEvent aEvent = new AEvent(A)
aEvent.Add(handler);
a.Invoke();
}
One approach I haven't seen here would be to create an object which has delegates for subscribe and unsubscribe. Here is a complete example program.
class Program
{
private event EventHandler<EventArgs> eventHandler;
public static void Main(string[] args)
{
Program program = new Program();
Thing thing = new Thing(new EventWrapper<EventArgs>(
delegate(EventHandler<EventArgs> handler) { program.eventHandler += handler; },
delegate(EventHandler<EventArgs> handler) { program.eventHandler -= handler; }
));
// events are fired
program.eventHandler?.Invoke(program, EventArgs.Empty);
thing.Unsubscribe();
}
}
class Thing
{
private readonly Action<EventHandler<EventArgs>> _unsubscribeEventHandler;
public Thing(EventWrapper<EventArgs> eventHandler)
{
this._unsubscribeEventHandler = eventHandler.Unsubscribe;
eventHandler.Subscribe?.Invoke(OnEvent);
Console.WriteLine("subscribed");
}
private void OnEvent(object? sender, EventArgs e)
{
Console.WriteLine("event fired");
}
public void Unsubscribe()
{
_unsubscribeEventHandler?.Invoke(OnEvent);
Console.WriteLine("unsubscribed");
}
}
class EventWrapper<T> where T : EventArgs
{
public Action<EventHandler<T>> Subscribe { get; private set; }
public Action<EventHandler<T>> Unsubscribe { get; private set; }
public EventWrapper(Action<EventHandler<T>> subscribe, Action<EventHandler<T>> unsubscribe)
{
Subscribe = subscribe;
Unsubscribe = unsubscribe;
}
}
In this example, we created a new class called EventWrapper<T> which wraps delegates for += and -= and exposes them with Subscribe and Unsubscribe methods. The delegates will need to be created by the class which created the event.

Categories

Resources