views:

138

answers:

6

Maybe I'm slow, but I just don't get why you would ever use an event that is not derived from an actual action (like clicking). Why go through the rigamarole of creating delegates and events when you can just call a method? It seems like when you create an event, all you're doing is creating a way for the caller to go through some complicated process to call a simple method. And the caller has to raise the event themselves! I don't get it.

Or maybe I'm just not grasping the concept. I get the need for events like OnClick and interactions with controls, but what about for classes? I tried to implement events for a class of mine, say, when the source of an item changed, but quickly realized that there was no point since I could just call a method whenever I wanted to perform a certain action instead of creating an event, raising an event, and writing an event handler. Plus, I can reuse my method, whereas I can't necessarily reuse my event handler.

Someone set me straight please. I feel like I'm just wrong here, and I want to be corrected. The last question I asked didn't really garner any sort of helpful answer.

Thanks.

+3  A: 

Events in general can be a good way to decouple the listener/observer from the caller/raiser.

Consider the button. When someone clicks on the button, the click event fires. Does the listener of the button click care what the button looks like, does, or anything of that nature? Most likely not. It only cares that the click action has taken place, and it now goes and does something.

The same thing can be applied to anything that needs to same isolation/decoupling. It doesn't have to be UI driven, it can just be a logic separation that needs to take place.

Joseph
but what if i want the object itself to do something on an event? i don't care what something else does when my event happens, i want the effect to take place in the object itself...
Jason
and like i said, i understand the need for events for a button or something where actual interaction is taking place between software and user, but what about inter-software?
Jason
An object will usually not catch its own events. Generally, if an object needs to do something at a particular time, it will do it on it's own. But if it also needs to notify other objects, it will raise an event, which any interested objects can handle.
Brian
+2  A: 

Using events has the advantage of separating the class(es) which handle events from the classes which raise them (a la the Observer Pattern). While this is useful for Model View Controller (the button which raises click events is orthogonal to the class that handles them), it is also useful any time you want to make it easy to (whether at runtime or not) to keep the class which handles the events separated from the class which raises them (allowing you to change or replace them).

Basically, the whole point is to keep the classes which handle the events separated from the classes which raise them. Unnecessary coupling is bad, since it makes code maintainence much more difficult (since a change in one place in code will require changes in any pieces of code coupled to it).

Edit: The majority of the event-handling you will do in Asp.Net will probably be to handle events from classes that are provided to you. Because such classes use event-handling, it makes it easy for you to interface with them. Often, the event will also serve to allow you to interact with the object that raised the event. For example, the databound controls usually raise an event right before they connect to the database, which you can handle in order to use runtime information to alter the arguments being passed to the stored procedure talking to your database, e.g. if the query string provides a page number parameter and the stored procedure has a page number argument.

Brian
ok so let me get this straight: the object creates events that can be listened to. it then raises its OWN events INTERNALLY, and then the caller handles those events however it wants? hmm... that actually makes some sense...
Jason
+1  A: 

Events can be used like messages to notify that something has happened, and an consumer can react to them in an appropriate way, so different components are loosely coupled. There's lots of things you can use events for, one example is auditing things that are happening in the system; the auditing component can consume various events and write out to a log when they are fired.

Charlie
+8  A: 

I've always like the Radio Station metaphor.

When a radio station wants to broadcast something, it just sends it out. It doesn't need to know if there is actually anybody out there listening. Your radio is able to register itself with the radio station (by tuning in with the dial), and all radio station broadcasts (events in our little metaphor) are received by the radio who translates them into sound.

Without this registration (or event) mechanism. The radio station would have to contact each and every radio in turn and ask if it wanted the broadcast, if your radio said yes, then send the signal to it directly.

Your code may follow a very similar paradigm, where one class performs an action, but that class may not know, or may not want to know who will care about, or act on that action taking place. So it provides a way for any object to register or unregister itself for notification that the action has taken place.

Matthew Vines
this makes a lot more sense to me. thanks. basically, if you want to handle an event, here's a way to do so. if not, so what. i think i get it now.
Jason
Google the Observer Pattern, which is really all events are. I think it will make a little more sense to you if you read a few articles on the pattern.
Matthew Vines
+1 For providing an easily understood, less technical explanation. I haven't heard that way of putting it before, but it's a good one.
Brian
+1 - Very similar metaphor to the one used in Head First Design Patterns to describe the Observer Pattern. I can't recommend this book enough for clear explanations - http://www.amazon.co.uk/Head-First-Design-Patterns-Freeman/dp/0596007124
Russ Cam
+1  A: 

The things that you seem to be missing are two:

  • There are happenings in software that can take an arbitrary amount of time not only due to waiting for user input (async i/o, database queries and so on). If you launch an async i/o request you would want to subscribe to the event notifying you when the reading is done so you can do something with the data. This idea is generalized in .NET's BackgroundWorker class, which allows you to do heavy tasks in the background (another thread) and receive notifications in the calling thread when it's done.

  • There are happenings in software that are used by multiple clients not only a single one. For instance, if you have a plugin architecture where your main code offers hooks to plugin code, you could either do something like

    foreach (Plugin p in getAvaliablePlugins()) { p.hook1(); }
    

    in every hook all over your code which reduces flexibility (p cannot decide what to do, and has to provide the hook1 method publicly) or you can just

    raiseEvent(hook1,this)
    

    where all registered plugins can execute their code because they receive the event, letting them do their job as they see fit.

Vinko Vrsalovic
+1  A: 

I think you're confusing ASP.NET's (mis)use of events, with plain ol' event handling.

We'll start with plain ol' event handling. Events is a (yet another) way of fulfilling the "Open [for extension]/Closed [for modification]" principle. When your class exposes an event, it allows external classes (perhaps classes that aren't even thought of, much less built, yet) to have code run by your class. That's a pretty powerful extension mechanism, and it doesn't require your class to be modified in any way.

As an example, consider a web server, that knows how to accept a request, but doesn't know how to process a file (I'll use bi-directional events here, where the handler can pass data back to the event source. Some would argue that's not kosher, but it's the first example that came to mind):

class WebServer {
   public event EventHandler<RequestReceivedEventArgs> RequestReceived;

   void ReceiveRequest() {
     // lots of uninteresting network code here
     var e = new RequestReceivedEventArgs();
     e.Request = ReadRequest();
     OnRequestReceived(e);
     WriteResponse(e.Response);
   }

   void OnRequestReceived(RequestReceivedEventArgs e) {
      var h = RequestReceived;
      if (h != null) h(e);
   }
}

Without changing the source code of that class - maybe it's in a 3rd party library - I can add a class that knows how to read a file from disk:

class FileRequestProcessor {
   void WebServer_RequestReceived(object sender, EventArgs e) {
      e.Response = File.ReadAllText(e.Request);
   }
}

Or, maybe an ASP.NET compiler:

class AspNetRequestProcessor {
   void WebServer_RequestReceived(object sender, EventArgs e) {
      var p = Compile(e.Request);
      e.Response = p.Render();
   }
}

Or, maybe I'm just interested in knowing that an event happened, without affecting it at all. Say, for logging:

class LogRequestProcessor {
   void WebServer_RequestReceived(object sender, EventArgs e) {
      File.WriteAllText("log.txt", e.Request);
   }
}

All of these classes are basically "injecting" code in the middle of WebServer.OnRequestReceived.

Now, for the ugly part. ASP.NET has this annoying little habit of having you write event handlers to handle your own events. So, the class that you're inheriting from (System.Web.UI.Page) has an event called Load:

 abstract class Page {
    public event EventHandler Load;

    virtual void OnLoad(EventArgs e) {
       var h = this.Load;
       if (h != null) h(e);
    }
 }

and you want to run code when the page is loaded. Following the Open/Closed Principle, we can either inherit and override:

 class MyPage : Page {
    override void OnLoad(EventArgs e) {
       base.OnLoad(e);
       Response.Write("Hello World!");
    }
 }

or use eventing:

 class MyPage : Page {
    MyPage() {
       this.Load += Page_Load;
    }

    void Page_Load(EventArgs e) {
       Response.Write("Hello World!");
    }
 }

For some reason, Visual Studio and ASP.NET prefer the eventing approach. I suppose you can then have multiple handlers for the Load event, and they would all get run auto-magically - but I never see anyone doing that. Personally, I prefer the override approach - I think it's a bit clearer and you'll never have the question of "why am I subscribed to my own events?".

Mark Brackett
thank you for this clear explanation.
Jason