Self-Referencing in Event Listener Delegates (C#) -
this perhaps question of semantics, perhaps not, ask: there appreciable difference in following 2 snippets?
public parent() { child newchild = new child(); newchild.requestspecialevent += (sender, e) => { newchild.domagic(); } }
or
public parent() { child newchild = new child(); newchild.requestspecialevent += (sender, e) => { ((child)sender).domagic(); } }
obvious difference option 1 sort of self-references itself, while option 2 performs cast on object. performance wise, expect cast more expensive.
however, i'm theorizing in option 1, technically "parent" holds reference "newchild" (through delegate defined within parent), if newchild goes away (newchild = null or similar), newchild object can't garbage collected (gc'ed) because parent has defined delegate still attached it. newchild can gc'ed when parent goes away.
however, in option 2, parent never creates such "hard reference" newchild, when newchild = null happens, can gc'ed immediately.
i prefer option 1 succinctness , readability, worry option 2 better. thoughts? theory correct or off-base? there alternative or more preferred approach (with sound reasoning) declaring same event listener relationship parent/child classes?
response @striplingwarrior:
in regards garbage collection, i'm still little skeptical. delegate references newchild, me seems newchild can't go away until delegate goes away. delegate go away if newchild goes away...but still newchild can't go away until delegate goes away! seems circular (almost). seems have happen:
//newchild = null; //this alone won't free newchild object because delegate still //points newchild object. //instead, has happen newchild.requestspecialevent = null; //destroys circular reference newchild newchild = null; //truly lets newchild object gc'd
or maybe saying 'newchild = null;' only, newchild.requestspecialevent stops pointing @ delegate, allows delegate go away, allows newchild go away? maybe talked myself answer. :)
your thoughts seem pretty spot-on, except i'm pretty sure newchild
still garbage-collected in option 1, because delegate references referenced handler on newchild
itself.
the 2 snippets functionally equivalent, option 1 using slightly more memory due reference in delegate, going faster when invoked since avoids cast. difference either way negligible i'd suggest using whichever feels cleanest (#1, if ask me).
the time i'd go #2 if want apply same delegate number of controls. in case, end using less memory:
var handler = new requestspecialeventhandler((sender, e) => { ((child)sender).domagic(); }); foreach(var child in children) { child.requestspecialevent += handler; }
and 1 other caveat aware of since option #1 refers newchild
variable, if value of variable changes later in method, new value used when handler invoked. example, in example:
foreach(var child in children) { child.requestspecialevent += (sender, e) => { // beware: don't this! modified closure! child.domagic(); }; }
... time event fires on of these children, "magic" performed n times only on last child in children
collection.
Comments
Post a Comment