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