I was wondering what the exact use of events is in c#. I am still in the process of learning c# so I maybe missing something but is it possible to just use delegates.
In this example I wrote a class with a method that counts from 0 to 2^64 and every time it reaches a multiple of a thousand raises an event. Here is the code:
namespace EventDelegate
{
class Program
{
static void Main(string[] args)
{
EventRaiserClass _eventraiser = new EventRaiserClass();
_eventraiser.handler = SomeEventHandler;
_eventraiser.handler += AnotherEventHandler;
_eventraiser.Loop();
Console.Read();
}
static void SomeEventHandler(object sender, EventArgs args)
{
Console.WriteLine("Event raised");
}
static void AnotherEventHandler(object sendr, EventArgs args)
{
Console.WriteLine("Event raised (Another handler)");
}
}
public delegate void Handler(object sender, EventArgs args);
class EventRaiserClass
{
public Handler handler;
public void Loop()
{
for (long i = 0; i < Int64.MaxValue; i++)
{
if ((i % 1000) == 0)
{
EventArgs args = new EventArgs();
RaiseEvent(args);
System.Threading.Thread.Sleep(1000);
}
}
}
private void RaiseEvent(EventArgs args)
{
if (handler != null)
handler(this, args);
}
}
}
What would the difference have been if I had declared the handler delegate variable to be an event like this public event Handler handler.
Sorry if I am been a bit vague or missing something obvious, but I am just wondering if something else happens behind the scenes when using event rather just using delegates or if it's just for readability purposes.
Events and delegates are similar, but events are more restricted, for good reasons.
In your code, you could do all kinds of things with _eventraiser.handler from the outside. You aren't supposed to do most of those things though.
Consider this line:
_eventraiser.handler = SomeEventHandler;
If you use delegates, you would have to check every time you try to attach an event handler if the delegate is null, and then initialize it with =, and if it is not null, you just have to add handlers with +=. If you forget an initialization, you get a null reference exception, if you put in one too many, you will overwrite all the previous things.
If you use events instead of delegates in this example, you don't have to do any of this, and, in fact, you can't even do it. With delegates you could even take it and then pass it around to some other classes, which could potentially be very dangerous.
The same goes for Invoke, and all the other things you can do with a delegate: They aren't there for events. The only things you can do with an event from an outside class is += and -=, that's it. You can view them as delegates with a special public interface with complicated getters and setters.
(Events also have a special add and remove syntax, but that's a rather uncommonly used feature)
Related
I have been wondering whether it would be worth implementing weak events (where they are appropriate) using something like the following (rough proof of concept code):
class Foo {
private WeakEvent<EventArgs> _explodedEvent = new WeakEvent<EventArgs>();
public event WeakEvent<EventArgs>.EventHandler Exploded {
add { _explodedEvent += value; }
remove { _explodedEvent -= value; }
}
private void OnExploded() {
_explodedEvent.Invoke(this, EventArgs.Empty);
}
public void Explode() {
OnExploded();
}
}
Allowing other classes to subscribe and unsubscribe from events with the more conventional C# syntax whilst under the hood actually being implemented with weak references:
static void Main(string[] args) {
var foo = new Foo();
foo.Exploded += (sender, e) => Console.WriteLine("Exploded!");
foo.Explode();
foo.Explode();
foo.Explode();
Console.ReadKey();
}
Where the WeakEvent<TEventArgs> helper class is defined as follows:
public class WeakEvent<TEventArgs> where TEventArgs : EventArgs {
public delegate void EventHandler(object sender, TEventArgs e);
private List<WeakReference> _handlers = new List<WeakReference>();
public void Invoke(object sender, TEventArgs e) {
foreach (var handler in _handlers)
((EventHandler)handler.Target).Invoke(sender, e);
}
public static WeakEvent<TEventArgs> operator + (WeakEvent<TEventArgs> e, EventHandler handler) {
e._handlers.Add(new WeakReference(handler));
return e;
}
public static WeakEvent<TEventArgs> operator - (WeakEvent<TEventArgs> e, EventHandler handler) {
e._handlers.RemoveAll(x => (EventHandler)x.Target == handler);
return e;
}
}
Is this a good approach? are there any undesirable side effects to this approach?
That's a bad idea because:
Your program starts to become non-deterministic because side-effects depend on the actions of the GC.
GCHandles come at a performance cost.
See the linked answer. It's a 95% duplicate but not quite enough to close the question I think. I'll quote the most relevant parts:
There also is a semantic difference and non-determinism that would be caused by weak references. If you hook up () => LaunchMissiles() to some event you might find the missiles to be launched just sometimes. Other times the GC has already taken away the handler. This could be solved with dependent handles which introduce yet another level of complexity.
I personally find it rare that the strong referencing nature of events is a problem. Often, events are hooked up between objects that have the same or very similar lifetime. For example you can hook up events all you want in the context of an HTTP request in ASP.NET because everything will be eligible for collection when the request has ended. Any leaks are bounded in size and short lived.
A few comments about your particular implementation:
Check the value of handler.Target for null before invoking it so that you don't try to do it with an object that has been disposed.
C# has special access rules for how you can use events. You cannot do a.Event1 = a.Event2 + SomeOtherMethod unless that code has private access to the events. This is allowed for delegates however. Your implementation behaves much more like a delegate instead of an event. This is probably not a major concern but something to think about.
Your operator methods should return a new object instead of modifying the first argument and returning it. Implementing operator + allows for syntax like the following: a = b + c, but in your implementation, you are modifying the state of b!. This is not kosher for how one would expect these operators to work; you need to return a new object instead of modifying the existing one. (Also, because of this your implementation is not thread-safe. Calling operator + from one thread while another was raising the event would raise an exception because the collection was modified during the foreach.)
I may be misunderstanding something fundamental here as I'm new to these concepts so please bear with me.
I'm currently removing methods from an event like so:
scheduleView.TouchDown -= scheduleView_TouchDown;
And then on other occasions - adding the methods:
scheduleView.TouchDown += scheduleView_TouchDown;
It all works fine so far, and I can understand it's possible to add several methods, like so:
scheduleView.TouchDown += scheduleView_TouchDown;
scheduleView.TouchDown += scheduleView_AnotherTouchDownEventHandler;
But how would I then later check what methods were wired up to this event?
Interestingly, you can't (at least, from the outside). An event is only obliged to offer 2 accessors - add and remove. There are other accessor methods defined in the CLI spec, but they aren't used in C# or anywhere else AFAIK. The key point: we can't ask an event what is subscribed (and indeed, we shouldn't need to know). All you can do is: add or remove.
If you are worried about double-subscribing, then note that if you try to unsubscribe and you haven't actually subscribed, then under every sane implementation this is simply a no-op; which means you can do:
// make sure we are subscribed once but **only** once
scheduleView.TouchDown -= scheduleView_TouchDown;
scheduleView.TouchDown += scheduleView_TouchDown;
From the perspective of the code raising the event, you rarely need to know who - simply:
// note I'm assuming a "field-like event" implementation here; otherwise,
// change this to refer to the backing-field, or the delegate from the
// event-handler-list
var handler = TouchDown;
if(handler != null) handler(this, EventArgs.Empty); // or similar
There is also a way to break the delegate list into individual subscribers, but it is very rarely needed:
var handler = TouchDown;
if(handler != null) {
foreach(EventHandler subscriber in handler.GetInvocationList()) {
subscriber(this, EventArgs.Empty);
}
}
The main uses for this are:
when you want to perform exception-handling on a per-subscriber basis
when the delegate returns a value or changes state, and you need to handle that on a per-subscriber basis
Yes: If you are within the class that publishes the Event, you can just access the delegate, and you can call the GetInvocationList method to get a list of the subscribers.
No: If you are working outside the class, as the delegate is not exposed to you. You could use reflection to get at it, but that would be a hack, at best.
In the type that declares the event, you can use GetInvocationList() to find out which delegates are subscribed:
public class EventProvider
{
public event EventHandler SomeEvent;
protected virtual void OnSomeEvent(EventArgs args)
{
if (SomeEvent != null)
{
var delegates = SomeEvent.GetInvocationList();
foreach (var del in delegates)
{
Console.WriteLine("{0} has subscribed to SomeEvent", del.Method.Name);
}
SomeEvent(this, args);
}
}
public void RaiseSomeEvent()
{
OnSomeEvent(EventArgs.Empty);
}
}
public class Program
{
public static void Main()
{
EventProvider provider = new EventProvider();
provider.SomeEvent += Callback1;
provider.SomeEvent += Callback2;
provider.RaiseSomeEvent();
}
public static void Callback1(object sender, EventArgs e)
{
Console.WriteLine("Callback 1!");
}
public static void Callback2(object sender, EventArgs e)
{
Console.WriteLine("Callback 2!");
}
}
This produces the following output:
Callback1 has subscribed to SomeEvent
Callback2 has subscribed to SomeEvent
Callback 1!
Callback 2!
I'm fairly convinced that this isn't possible, but I'm going to ask nonetheless.
In order to make a single-shot subscription to events, I frequently find myself using this (self-invented) pattern:
EventHandler handler=null;
handler = (sender, e) =>
{
SomeEvent -= handler;
Initialize();
};
SomeEvent += handler;
It's quite a lot of boiler-plate, and it also makes Resharper whinge about modified closures. Is there a way of turning this pattern into an extension method or similar? A better way of doing it?
Ideally, I'd like something like:
SomeEvent.OneShot(handler)
It's not very easy to refactor to an extension method, because the only way you can refer to an event in C# is by subscribing (+=) to or unsubscribing (-=) from it (unless it's declared in the current class).
You could use the same approach as in Reactive Extensions: Observable.FromEvent takes two delegates to subscribe to the event an unsubscribe from it. So you could do something like that:
public static class EventHelper
{
public static void SubscribeOneShot(
Action<EventHandler> subscribe,
Action<EventHandler> unsubscribe,
EventHandler handler)
{
EventHandler actualHandler = null;
actualHandler = (sender, e) =>
{
unsubscribe(actualHandler);
handler(sender, e);
};
subscribe(actualHandler);
}
}
...
Foo f = new Foo();
EventHelper.SubscribeOneShot(
handler => f.Bar += handler,
handler => f.Bar -= handler,
(sender, e) => { /* whatever */ });
The following code works for me. It's not perfect to have to specify the event via a string, but I have no glue how to solve that. I guess it's not possible in the current C# version.
using System;
using System.Reflection;
namespace TestProject
{
public delegate void MyEventHandler(object sender, EventArgs e);
public class MyClass
{
public event MyEventHandler MyEvent;
public void TriggerMyEvent()
{
if (MyEvent != null)
{
MyEvent(null, null);
}
else
{
Console.WriteLine("No event handler registered.");
}
}
}
public static class MyExt
{
public static void OneShot<TA>(this TA instance, string eventName, MyEventHandler handler)
{
EventInfo i = typeof (TA).GetEvent(eventName);
MyEventHandler newHandler = null;
newHandler = (sender, e) =>
{
handler(sender, e);
i.RemoveEventHandler(instance, newHandler);
};
i.AddEventHandler(instance, newHandler);
}
}
public class Program
{
static void Main(string[] args)
{
MyClass c = new MyClass();
c.OneShot("MyEvent",(sender,e) => Console.WriteLine("Handler executed."));
c.TriggerMyEvent();
c.TriggerMyEvent();
}
}
}
I would suggest using a "custom" event so that you have access to the invocation list, and then raise the event by using Interlocked.Exchange to simultaneously read and clear the invocation list. If desired, event subscription/unsubscription/raising could be done in thread-safe manner by using a simple linked-list stack; when the event is raised, the code could, after the Interlocked.Exchange, reverse the order of stack items. For the unsubscribe method, I'd probably suggest simply setting a flag within the invocation-list item. This could in theory cause a memory leak if events were repeatedly subscribed and unsubscribed without the event ever being raised, but it would make for a very easy thread-safe unsubscribe method. If one wanted to avoid a memory leak, one could keep a count of how many unsubscribed events are still in the list; if too many unsubscribed events are in the list when an attempt is made to add a new one, the add method could go through the list and remove them. Still workable in entirely lock-free thread-safe code, but more complicated.
I have a static generic class that helps me move events around with very little overhead:
public static class MessageBus<T> where T : EventArgs
{
public static event EventHandler<T> MessageReceived;
public static void SendMessage(object sender, T message)
{
if (MessageReceived != null)
MessageReceived(sender, message);
}
}
To create a system-wide message bus, I simply need to define an EventArgs class to pass around any arbitrary bits of information:
class MyEventArgs : EventArgs
{
public string Message { get; set; }
}
Anywhere I'm interested in this event, I just wire up a handler:
MessageBus<MyEventArgs>.MessageReceived += (s,e) => DoSomething();
Likewise, triggering the event is just as easy:
MessageBus<MyEventArgs>.SendMessage(this, new MyEventArgs() {Message="hi mom"});
Using MessageBus and a custom EventArgs class lets me have an application wide message sink for a specific type of message. This comes in handy when you have several forms that, for example, display customer information and maybe a couple forms that update that information. None of the forms know about each other and none of them need to be wired to a static "super class".
I have a couple questions:
fxCop complains about using static methods with generics, but this is exactly what I'm after here. I want there to be exactly one MessageBus for each type of message handled. Using a static with a generic saves me from writing all the code that would maintain the list of MessageBus objects.
Are the listening objects being kept "alive" via the MessageReceived event?
For instance, perhaps I have this code in a Form.Load event:
MessageBus<CustomerChangedEventArgs>.MessageReceived += (s,e) => DoReload();
When the Form is Closed, is the Form being retained in memory because MessageReceived has a reference to its DoReload method? Should I be removing the reference when the form closes:
MessageBus<CustomerChangedEventArgs>.MessageReceived -= (s,e) => DoReload();
Well, yes, you should, but if you use the lambda syntax as you've done in your example I think it won't work (by which I mean, the handler will not be de-registered successfully).
Someone correct me if I'm wrong, but I believe this is true because using the lambda syntax effectively creates a new EventHandler<CustomerChangedEventArgs> object, with its own place in memory. When you try to remove this handler, using the lambda syntax again, this creates yet another new EventHandler<CustomerChangedEventArgs> object, which is not equal to the first one you created; and so the first one never gets de-registered.
Sadly, I think you'll need to actually define a method like this:
DoReload(object sender, CustomerChangedEventArgs e) {
DoReload(); // your original overload, which doesn't actually care
// about the sender and e parameters
}
This way you can do:
MessageBus<CustomerChangedEventArgs>.MessageReceived += DoReload;
And later:
MessageBus<CustomerChangedEventArgs>.MessageReceived -= DoReload;
Yes, there are problems. Your event handlers will cause the form object to stay referenced, you have to explicitly unregister the event handlers. The lambdas make this impossible, you'll have to write an explicit handler.
This pattern has a name, "Event Broker service". It is part of the Composite UI Application Block, published by Microsoft's Pattern and Practices team. Beg, borrow and steal (if not use) what you can from this.
You could use weak references to store the event handlers. That way, unhooked handlers won't prevent garbage collection of the objects.
public static class MessageBus<T> where T : EventArgs
{
private static List<WeakReference> _handlers = new List<WeakReference>();
public static event EventHandler<T> MessageReceived
{
add
{
_handlers.Add(new WeakReference(value));
}
remove
{
// also remove "dead" (garbage collected) handlers
_handlers.RemoveAll(wh => !wh.IsAlive || wh.Target.Equals(value));
}
}
public static void SendMessage(object sender, T message)
{
foreach(var weakHandler in _handlers)
{
if (weakHandler.IsAlive)
{
var handler = weakHandler.Target as EventHandler<T>;
handler(sender, message);
}
}
}
}
I have a static class that I would like to raise an event as part of a try catch block within a static method of that class.
For example in this method I would like to raise a custom event in the catch.
public static void saveMyMessage(String message)
{
try
{
//Do Database stuff
}
catch (Exception e)
{
//Raise custom event here
}
}
Thank you.
Important: be very careful about subscribing to a static event from instances. Static-to-static is fine, but a subscription from a static event to an instance handler is a great (read: very dangerous) way to keep that instance alive forever. GC will see the link, and will not collect the instance unless you unsubscribe (or use something like a WeakReference).
The pattern for creating static events is the same as instance events, just with static:
public static event EventHandler SomeEvent;
To make life easier (re null checking), a useful trick here is to add a trivial handler:
public static event EventHandler SomeEvent = delegate {};
Then you can simply invoke it without the null-check:
SomeEvent(null, EventArgs.Empty);
Note that because delegate instances are immutable, and de-referencing is thread-safe, there is never a race condition here, and no need to lock... who-ever is subscribed when we de-reference gets invoked.
(adjust for your own event-args etc).
This trick applies equally to instance events.
Your event would also need to be static:
public class ErrorEventArgs : EventArgs
{
private Exception error;
private string message;
public ErrorEventArgs(Exception ex, string msg)
{
error = ex;
message = msg;
}
public Exception Error
{
get { return error; }
}
public string Message
{
get { return message; }
}
}
public static class Service
{
public static EventHandler<ErrorEventArgs> OnError;
public static void SaveMyMessage(String message)
{
EventHandler<ErrorEventArgs> errorEvent = OnError;
if (errorEvent != null)
{
errorEvent(null, new ErrorEventArgs(null, message));
}
}
}
And Usage:
public class Test
{
public void OnError(object sender, ErrorEventArgs args)
{
Console.WriteLine(args.Message);
}
}
Test t = new Test();
Service.OnError += t.OnError;
Service.SaveMyMessage("Test message");
Several folks have offered up code examples, just don't fire an event using code such as:
if(null != ExampleEvent)
{
ExampleEvent(/* put parameters here, for events: sender, eventArgs */);
}
as this contains a race condition between when you check the event for null and when you actually fire the event. Instead use a simple variation:
MyEvent exampleEventCopy = ExampleEvent;
if(null != exampleEventCopy)
{
exampleEventCopy(/* put parameters here, for events: sender, eventArgs */);
}
This will copy any event subscribers into the exampleEventCopy, which you can then use as a local-only version of the public event without having to worry about any race conditions (Essentially, it is possible that another thread could pre-empt you right after you have checked the public event for null and proceed to remove all subscribers from the event, causing the subsequent firing of the event to throw an exception, by using a local-only copy, you avoid the possibility of another thread removing subscribers, since there is no way they could access the local variable).
Note: VS2008, C#
Just declare an event as you normally would within the static class, but be sure to mark the event as static:
public static event EventHandler Work;
Then just subscribe to it as you normally would.
Just to add "Delegates are immutable" So, as shown in the example above the following line obtains a copy of the delegate.
EventHandler<ErrorEventArgs> errorEvent = OnError;
The way I did this is the following:
1- define a delegate (this will enable you to have customized arguments):
public delegate void CustomeEventHandler(string str);
2- define an event based on the previously defined delegate:
public static event CustomeEventHandler ReadLine;
3- create an event handler:
static void OnLineRead(string currentLine)
{
if (ReadLine != null)
ReadLine(currentLine);
}
4- raise your event using the event handler (just call it wherever you want the event to be raised).