Reputation: 10804
I might be overthinking this one a little but I could use some help in identifying a way/the best way to do the following.
I have an event handler that is attached to an object that is a property of another class. In my event handler I need additional meta-data about the object that caused the event (i.e. the ID of the object it is contained in). From the sender and the event information there is no way to obtain the information I need. My inclination was that this would be a good place to use a captured variable but I'm unsure of my implementation ideas.
So to illustrate in code I have an event handler:
void MyEventHandler(object sender, EventArgs e){
//Do Stuff here
}
(As a note I'm using base EventArgs here but in my actual implementation the are a specialized subclass and the event is declared using the generic EventHandler)
I am currently attaching it like this:
topObject.SubObject.EventToHandle += MyEventHandler;
I later detatch it like so:
topObject.SubObject.EventToHandle -= MyEventHandler;
I want topObject's ID when I'm handling the event so I was going to change the MyEventHandler to have the following signature:
void MyEventHandler(int id, object sender, EventArgs e)
and attach the event handler like this:
topObject.SubObject.EventToHandle += (s,e) => MyEventHandler(topObject.ID, s,e);
My concern with that is two fold.
Because of those two concerns my thought was to create an Action and save the action and use it until I needed to remove the event handler. I did the following:
Action<object, EventArgs> handler = (s,e) => MyEventHandler(topObject.ID, s,e);
topObject.SubObject.EventToHandle += handler;
I get that the action cannot be casted to an event handler. Is there some easy way that I can make this transformation that will still ensure that I can detach the event handler? Am i just over thinking this/ is there a way I'm not seeing right now to do this?
Upvotes: 1
Views: 2458
Reputation: 294287
Don't change the signature of the event. While the CLR allows, technically, for any signature for an event, there are reasons why the entire Framework was designed with events having the signature (object sender, EventArgs args)
. In fact, there is an FxCop rule for events that violate this signature, CA1009: Declare event handlers correctly:
Event handler methods take two parameters. The first is of type System.Object and is named 'sender'. This is the object that raised the event. The second parameter is of type System.EventArgs and is named 'e'.
There are several solutions (alternatives):
Upvotes: 0
Reputation: 6159
If the event handler needs the top object's Id, I would guess it would not break some abstraction layer in your design to make them aware of eachother.
In other words, your event handler can look like this:
void Handler(object sender, EventArgs e)
{
var s = (SubObject) sender;
int id = s.TopObject.ID;
// do something with id...
}
I would keep event signatures in the convention of sender and args.
Upvotes: 0
Reputation: 138925
An event handler signature in the class raising the event should be:
protected void OnMyEvent(object sender, EventArgs e)
{
....
}
or
protected void OnMyEvent(object sender, MyEventArgs e)
{
....
}
In this case, the caller would do this kind of code:
topObject.SubObject.MyEvent -= OnSubObjectMyEvent;
and implement OnSubObjectMyEvent like this (example):
private void OnSubObjectMyEvent(object sender, MyEventArgs e)
{
int topObjectId = ((SubObjectType)sender).TopObject.Id;
...
}
Here I suppose SubObject has a TopObject property that allows me to get the top object's id.
That's the way most .NET Framework classes work. Is there anything wrong with this approach?
Upvotes: 0
Reputation: 2640
You can create all nice wrapper functions that wrap existing event-handlers and supply them with object ids, but you will still have to store the resulting delegate explicitly to unsubscribe the event.
The only nice way I see to do it without ugly wrappers is using reactive extensions. It essentially allows you to transform your event to an IObservable, and then you can apply any operator to the resulting IObservable (for example Select will do the job in your case). But it's still no that elegant.
Upvotes: 1