Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I am fairly happy with my understanding of the .NET event model. I think I might be misunderstanding a small nuance of the system.

When I started out putting events into my classes I would use the standard way like so:

public event EventHandler<MyEventArgs> MyEvent;

This meant that anything subscribing to the event would need a method like:

void HandleThatEvent(object sender, MyEventArgs args){...}

Which is nice, but I found that I would rarely care about the sender, so it made a lot of method signatures bloated.

So I switched to declaring my own delegate types

public delegate void MyEventHandler(SomeClass argument);

Which cut down on clutter, but left me with a small problem when it came to writing handlers:

eventImplmentor.MyEvent += HandleThatEvent;
.
.
.
void HandleThatEvent(/*oh, um, what arguments does it take? Intellisense isn't telling me*/)

So I would have to go back to the declaration of the delegate and look and then go back and write them in, or compile it and wait to be told.

So now instead, I'm just using Action, Action<T> or whatever template fits.

public event Action<SomeClass> MyEvent;

So that I can hover over the event and be told what parameters it expects.

My question, after all that: Is there a best practice for declaring events in C#? Should I go back to the EventHandler<T> way, or is Action<T> acceptable?

share|improve this question
    
Don't forget to make sure the handler is locally copied to where you fire the event, always want to do this for thread safety. – StevieV Mar 9 at 22:17
    
You can write your own smart, mean & lean type-safe events in encapsulated code but anything you publish should follow the standard pattern or it will just confuse the users of your class (and apparently some tools too). – Martin Maat Jul 2 at 22:37

For simple, internal event handling, there are those that simply use Action or Action<T>, as you are proposing. I tend to use the standard pattern, including the Sender, even for internal events, because you never know when you might later want to expose a class or event, and I would not want the penalty of having to refactor the event method just to make it public.

I do agree with you that the event handling signature is a bit heavier than it should be for simple scenarios, but it is well designed to handle incremental migration as additional event arguments could become necessary over time. Overall, I would stick with the standard pattern, especially since, as you noted, you only get proper IntelliSense support if you do.

For what it's worth, I put some time into this and came up with a different event handling pattern: Event Signature in .NET — Using a Strong Typed 'Sender'?. The goal here was not to remove the Sender, but to make it generically strong typed as TSender instead of weakly typed as System.Object. It works very well; however, one does lose IntelliSense support when you do this, so there is an unfortunate trade-off.

Overall, I would stick with the standard pattern, but it is interesting to think about potentially better ways to do this.

share|improve this answer
    
Thanks for pointing me to your SO question. It's very interesting. I still don't understand why it's so important that the sender is mandatory. Most of the time I don't care about the sender. Is it just some arbitrary MS rule? – Matt Ellen Apr 13 '11 at 11:00
    
No, of course you can declare your delegates however you like. It's .NET policy to always include the sender, and it's not entirely a bad idea at that. – Neil Apr 13 '11 at 11:04
    
@Neil: I understand that it use useful sometimes, but I don't get the policy of always doing it - especially since MS recommend doing events their way. One of the things I really like about events is the ability to decouple classes. If I'm including the object, then it's coupled back up again. If it's just a CLS compliance thing then I can live with that. – Matt Ellen Apr 13 '11 at 11:46
    
It's coupled back up again only if you use the sender object, otherwise it doesn't matter what gets put as the value of sender since you don't use it. Dependency exists only if you need there to be a dependency. I see where you're coming from, and if object sender disappeared from all code from any server on the planet, I wouldn't stay up nights. – Neil Apr 13 '11 at 12:19
    
Yes, you can send 'null' as the sender if you really want... But, by including the Sender, the event handler itself could unsubscribe if it wanted to. Overall, though, I would say that knowing the source of the event is usually pretty important. – Mike Rosenblum Apr 13 '11 at 23:19

I think that using EventHandlerT> is good because if you use a custom class that inherits form System.EventArgs for the type parameter T, then you can define a handler for many different events. For example if we want to deal with the related classes class Car and class Boat in the same method, we can define the following event arg classes:

public class CarEventArgs : System.EventArgs
{
    public readonly string msg;
    public CarEventArgs(string message ="")
    {
        msg = message;
    }
}

public class BoatEventArgs : System.EventArgs
{
    public readonly string msg;
    public BoatEventArgs(string message ="")
    {
        msg = message;
    }
}

Now we can have the following method to deal with both boats and cars:

public static void TransportationMethod(object sender, EventArgs e)
{
    if (sender is Car && e is CarEventArgs)
    { 
        Car car = (Car)sender;
        CarEventArgs carArgs = (CarEventArgs)e;
        .
        .
        .
    }

    if (sender is Boat && e is BoatEventArgs)
    { 
        Boat boat = (Boat)sender;
        BoatEventArgs boatArgs = (BoatEventArgs)e;
        .
        .
        .
    }
}
share|improve this answer
1  
this sort of "switching on type" is considered bad OOP. what do you gain by putting two pieces of unrelated code in the same method? all you're doing is getting less type safety. – kai Jul 2 at 21:18
    
I think that if you read my post closer, you will see that I stated the Boat and Car classes are related. So if you want to treat to class types similarly, you might want to put them in the same method. – sericks Jul 2 at 21:29
    
Or if you wanted to, you could have Boat and Car inherit from the class Vehicle and use polymorphism to treat them same. In this case you might want a VehicleEventArgs class that inherits from System.EventArgs, and have both BoatEventArgs and CarEventArgs inherit from VehicleEventArgs. – sericks Jul 2 at 21:41
2  
but you are NOT treating them the same way, you are branching based on their type. polymorphism is indeed the prefered way to deal with this. this handler isn't handling "vehicles". it's handling "cars and boats". handling cars is done in a completely different manner than handling boats here, because two completely different and mutually exclusive code blocks are run. in short, you are violating the "tell, don't ask" principle. – kai Jul 2 at 22:03
1  
TDA isn't specifically about state, although that is the most common way it's applied. The core principle is about how you shouldn't query an object and then take action based on the return value. You should tell the object what you want it to do. It helps a truckload with reducing duplication of logic and tends to make your methods shorter and more readable/maintainable – kai Jul 3 at 6:51

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.