Any Opinions on the 'Sender As Object' Event Argument?

Mike_R

Junior Contributor
Joined
Oct 20, 2003
Messages
316
Location
NYC
I'm not quite sure why I'm bugged by this, but does anyone have an opinion as to why the .NET rules regarding custom Event Arguments is that the 'sender' parameter be typed 'As Object'? Why not strong-type it to the actual type of the sender? For that matter, why have a separate parameter at all; why not have it included within the 'e As EventArguments' parameter, and then the handler can utilize 'e.Sender' as needed?

Any thoughts on this? For the life of me I can't think of one good reason for keeping 'Sender As Object' and so I'm thinking of strong-typing my Events... However, this would be non-standard, so I was wondering if anyone knew or could explain the rationale behind this?

Thanks in advance!
Mike
 
I believe the reason that 'sender as object' is used, is because this enables a single event handler to handle more than one differen't type of object. If for example you wrote an event for clearing items on a form you could do..
C#:
if(sender is Textbox)
{
((Textbox)sender).Text = "";
}
else if(sender is RadioBox)
{
// do something else
}
... then attach the event to any type of control.

This is only my opinion, somebody with a bit more knowledge may well correct me.
 
Hey Cags,

Yeah, you know, I think you are dead-on. I was just comming to this realization and was about to post this idea myself.

Still, I would think that 99.9% of the time that one is dealing with either a single 'sender' type, or perhaps the 'sender' is a base class, such as a control, whereby the handler could discern using .GetType and then lcast to Button, or TextBox, etc. as needed and so strong-typing the handler using 'sender As Control' would still seem to be valid here, where each event actually fires a 'sender As TextBox' or what-have-you, where the 'sender' is inheriting from 'control'.

So, I guess using Sender As Object is the most flexible, but I wonder how bad it would be, really, to strong-type it? It just "feels" better if strong-typed I think; the handler having to cast the object to the required type when you *know* what it is, but the compiler doesn't, just feels lousy. :(

Just thinking out loud, I guess...
 
Last edited:
For the few events that I've created, I used custom delegates that didn't follow the standard "sender as object" parameter. The other developers I've worked with that saw the code knew instantly what was being passed and why so there was no confusion.

I've rarely had the need to use and the sender parameter in my events as I usually have one event per object and I don't generally point multiple instances to use the same event. Maybe I don't know enough to use them correctly? :)

As an example, I have a small batch job that reads and parses a file and then does some other stuff. The parser object uses a delegate declared like so:
C#:
delegate void LineProcessed(int currentLine, System.ComponentModel.CancelEventArgs e);

One of the classes using the delegate is declared like so:
C#:
    internal sealed class FileParser
    {
		private FileParser() {}

		#region Events
		public static event LineProcessed	OnLineParsed;
		public static event LineProcessed	OnLineScrubbed;
		public static event TotalChanged	OnTotalChanged;
		public static event ScrubStart		OnScrubStart;

		private static bool RaiseLineParsed()
		{
			CancelEventArgs args = new CancelEventArgs();
			if (OnLineParsed != null) OnLineParsed(parsedLines.Count, args);
			return !args.Cancel;
		}

		private static bool RaiseLineScrubbed()
		{
			CancelEventArgs args = new CancelEventArgs();

			int currentIndex = (parsedLines.CurrentIndex > parsedLines.Count) ? parsedLines.Count : parsedLines.CurrentIndex;
			if (OnLineScrubbed != null) OnLineScrubbed(currentIndex, args);
			return !args.Cancel;
		}

		private static bool RaiseTotalChanged(int totalLines)
		{
			CancelEventArgs args = new CancelEventArgs();
			if (OnTotalChanged != null) OnTotalChanged(totalLines, args);
			return !args.Cancel;
		}

		private static bool RaiseScrubStart(string message)
		{
			CancelEventArgs args = new CancelEventArgs();
			if (OnScrubStart != null) OnScrubStart(message, args);
			return !args.Cancel;
		}
		#endregion
...
}

The code inside of the FileParser classes calls RaiseNNN whenever it wants to raise an event. There's no need for the code consuming this class (and its events) to ever need access to the FileParser class itself, within the event, so I don't pass it.

The code in the consuming class hooks up the events like so:
C#:
FileParser.OnTotalChanged += new TotalChanged(OnTotalChanged);
FileParser.OnLineParsed += new LineProcessed(OnLineParsed);
FileParser.OnScrubStart += new ScrubStart(OnScrubStart);
FileParser.OnLineScrubbed += new LineProcessed(OnLineScrubbed);
lineList = FileParser.Parse(sourceFile);
FileParser.OnLineScrubbed -= new LineProcessed(OnLineScrubbed);
FileParser.OnScrubStart -= new ScrubStart(OnScrubStart);
FileParser.OnLineParsed -= new LineProcessed(OnLineParsed);
FileParser.OnTotalChanged -= new TotalChanged(OnTotalChanged);
Now, a separate question would be: Why the weird syntax to unhook an event? I hate having to declare a NEW instance of a delegate, to unhook the existing one. The syntax just seems awkward.

Having said all that, if I were making a custom control that could get sited on a form, I'd probably stick with the "sender as object" syntax, just in case someone wanted to hook up multiple instances to the same event.

-ner
 
Wow, thank you Nerseus for that outstanding reply...

The only thing that I did not quite understand was your line:
Now, a separate question would be: Why the weird syntax to unhook an event? I hate having to declare a NEW instance of a delegate, to unhook the existing one. The syntax just seems awkward.
I guess this is weird if you think about it, but I guess even though different "objects", the system must be discerning the address of the object passed into the delegate (along with the delegate's type) to determine if a delegate is the *same*? But what other syntax is there? (You refer to yours as "awkward", but I'm not sure why?) [Edit: Ok, I get, it, we're stuck with this syntax, and you don't like it, yeah, I get you... You can always switch to VB and use 'AddHandler' and 'RemoveHandler' instead! :p]

Overall, thank you so much for your feedback... Mostly, it makes me comfortable "thinking for myself" and therefore strong-typing the Delegate's or Event's 'sender' parameter and not worry too much about .NET rules on this. I do think that strong-typing it here makes the code clearer and more of a compile-time contract.

I suppose it would be kind of nice if the Event or Delegate could have a strong-typed definition such as 'sender As TextBox' while the Handler could use a widecasted definition of the same, such as 'sender As Control' or 'sender As Object', if one wanted to handle a "wider" definition of objects that could raise this Event. Unfortunately, however, it does seem that the Delegate-to-Handler and definitions have to match precisely, or the compiler complains...
 
Back
Top