Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Code-friendly version of event signature in .NET

Tags:

c#

.net

events

Preceding posts:

Event Signature in .NET — Using a Strong Typed 'Sender'?

In a C# event handler, why must the “sender” parameter be an object?


Microsoft's conventions and guidelines force .NET users to use special pattern for creating, raising and handling events in .NET.

Event design guidelines http://msdn.microsoft.com/en-us/library/ms229011.aspx state that


Citation:

The event-handler signature observes the following conventions :

  • The return type is Void.

  • The first parameter is named sender and is of type Object. This is the object that raised the event.

  • The second parameter is named e and is of type EventArgs or a derived class of EventArgs.This is the event-specific data.

  • The method takes exactly two parameters.


These conventions tell developers that the (following) shorter and more obvious code is evil:

public delegate void ConnectionEventHandler(Server sender, Connection connection);

public partial class Server
{
    protected virtual void OnClientConnected(Connection connection)
    {
        if (ClientConnected != null) ClientConnected(this, connection);
    }

    public event ConnectionEventHandler ClientConnected;
}

and the (following) longer and less obvious code is good:

public delegate void ConnectionEventHandler(object sender, ConnectionEventArgs e);

public class ConnectionEventArgs : EventArgs
{
    public Connection Connection { get; private set; }

    public ConnectionEventArgs(Connection connection)
    {
        this.Connection = connection;
    }
}

public partial class Server
{
    protected virtual void OnClientConnected(Connection connection)
    {
        if (ClientConnected != null) ClientConnected(this, new ConnectionEventArgs(connection));
    }

    public event ConnectionEventHandler ClientConnected;
}

Though these guidelines not state why is it so important to follow these conventions, making developers act like monkeys who don't know why and what are they doing.

IMHO, Microsoft's event signature conventions for .NET are bad for your code because they cause additional zero-efficiency effort to be spent on coding, coding, coding:

  1. Coding "(MyObject)sender" casts (not speaking about 99% of situations that don't require sender at all)
  2. Coding derived "MyEventArgs" for the data to be passed inside event handler.
  3. Coding dereferences (calling "e.MyData" when the data is required instead of just "data")

It's not that hard to do this effort, but practically speaking what are we loosing when not conforming to Microsoft's conventions, except that people take you as an heretic because your act of confrontation to Microsoft's conventions verges on blasphemy :)

Do you agree?

like image 323
Lu4 Avatar asked Jan 22 '23 02:01

Lu4


2 Answers

The problems you will have:

  1. When you add another argument, you will have to change your event handler signature.

  2. When a programmer first looks at your code, your event handlers will not look like event handlers.

Especially the latter can waste you far more time than writing a 5 line class.

like image 114
Stu Avatar answered Jan 23 '23 17:01

Stu


Regarding having a strongly-typed sender, I've often wondered that myself.

Regarding the EventArgs, I'd still recommend you use an intermediate EventArgs class because you may want to add event information in the future which you don't currently foresee. If you've used a specific EventArgs class all along, you can simply change the class itself and the code where it gets fired. If you pass the Connection as per your example, you'd have to refactor every event handler.

Edit

Jim Mischel made a good point in his comments. By making the sender an object, we enable the same event method to potentially be reused to handle a variety of events. For example, let's say that a grid needs to update itself if:

  • the user clicks a "refresh" button, or
  • the system detects that a new entry has been loaded from the server.

You could then say something like this:

serverBus.EntryReceived += RefreshNeededHandler;
refreshButton.Click += RefreshNeededHandler;

...
public void RefreshNeededHandler(object sender, EventArgs args) 
{
    ...
}

Of course, in practice, I have pretty much never had any call for this kind of reuse, whereas the first thing I tend to to in many, many cases is cast the sender to the object type that I know it has to be. If I want to reuse handlers like this, I think it would be easy enough to make two handlers that both call the same convenience method. For me, an event handler is conceptually supposed to handle a specific type of event on a particular group of objects. So I am not personally convinced that the object sender approach is the best convention.

However, I can imagine cases where this would be extremely handy, like if you want to log every event that gets fired.

like image 34
StriplingWarrior Avatar answered Jan 23 '23 16:01

StriplingWarrior