Fork me on GitHub

Tuesday, August 28, 2007

John "Delegate" Doe

It seems I've just experienced a unique little caveat of anonymous delegates. One of my favorite things about an anonymous method in .NET is that it can carry over variable values from the defining code into the definition of the method. Essentially this (which is just sample code and not a good reference for proper logging practice ;D):

private void RegisterClickLogger(string logTitle)
{
Log log = new Log(logTitle);
this.Click += delegate(object sender, EventArgs e)
{
log.Write("Clicked!");
};
}

will write "Clicked!" to the log object created as a local variable in the RegisterClickLogger method even though RegisterClickLogger has stopped executing. The purpose of this post isn't really to introduce this concept though, there are many views on proper usage and such for anonymous methods out there, but rather to point out a unique scenario that caused me to think a bit about it.

As some of you may have discovered through other annoying experiences (like myself :p), Dictionary stores it's values in a structure called KeyValuePair. The key here is that it's a "structure" (a Value Type), not a class (Reference Type). A common issue with this is that it complicates serialization (when using a Reference Type for one of the type parameters). Today, however, the following code through me for a bit of a loop:

foreach (KeyValuePair<string, Type> pair in s_tests)
{
b = new Button();
b.Text = pair.Key;
b.Click += delegate(object sender, EventArgs e)
{
Form f = (Form)Activator.CreateInstance(pair.Value);
f.ShowDialog(this);
f.Dispose();
f = null;
};
b.AutoSize = true;
flow.Controls.Add(b);
}


It seemed all was fine when I clicked the last button, but later when I needed to click one of the earlier buttons I noticed that the same Form was appearing for every button. Looking things over a bit I decided to try changing the code to this:

foreach (KeyValuePair<string, Type> pair in s_tests)
{
b = new Button();
b.Text = pair.Key;
Type t = pair.Value;
b.Click += delegate(object sender, EventArgs e)
{
Form f = (Form)Activator.CreateInstance(t);
f.ShowDialog(this);
f.Dispose();
f = null;
};
b.AutoSize = true;
flow.Controls.Add(b);
}

It's a very simple change, hardly noticeable really, but sure enough it did the job and my problem was solved. So what happened? Well I'd have to look into things a bit more to give a truly accurate, in depth answer, but from my initial impression it seems that the value of "pair" (that was referenced by all of the anonymous delegates created) was updated (as expected) through each iteration in the loop. When a delegate would finally get called the loop had finished iterating and pair was the value of the last item in the Dictionary. I should probably look into it a little further to identify whether this treatment is related to the fact that pair was a Value Type or if the declaration of the variable "t" inside the scope of the loop is the only reason it was solved (t being a Reference Type). I'm just curious because I don't recall all of the nuances of anonymous methods in .NET, though I'd venture a guess that the second possibility is more likely (though I would, so much like to have another reason to hate KeyValuePair being a Value Type).

Alas, there is never enough time and I must run, but I'll be back soon to discuss some developments in my research (as promised),

-TheXenocide

Friday, August 24, 2007

Minor Accomplishments in an Otherwise Hectic Life

You gotta love those swings and turns life throws at ya, eh? I won't bore you with torrents of dry complaints or excuses; suffice it to say life is plenty good enough to ignore a few bumps in the road.

On a slightly more positive note, I've found time to complete a small project! Nothing terribly exciting or related to my larger scale goals (more on those later); something useful and fun none-the-less. If you're not an iGoogle user you're simply not as cool as me :p. Kidding, but really, I love Google; use it all the time (I mean like alot!), and I'm a big fan of the veritable plethora of goodies and usage features tucked away in the depths of iGoogle. Somewhat recently I stumbled upon a couple of gadgets I always wanted but never got around to writing myself.

"Your Page Here" was something I had always wished for; nothing like bringing a few more commonly used things to your homepage--load on demand web page in it's own tab sounded great!

Another thing I wanted, since I'm a screen real-estate whore (even with multiple monitors or HDTVs I'm stingy as all hell :p), was something that could hide the header and footer of the page. This was the first gadget I considered making myself (if you want to be my pimp it's gonna cost you a full 5 flat-panel setup and 4 graphics cards ;D). Luckily, i thought one day, some other people wrote them for me! I found two decent ones in the Directory: "No Google Header" and "Homepage Header Toggler" both of which were rather sufficient, I'd say different people would pick either for their own reasons.

Today, however, I ran into a problem. I actually wanted to use these things today, and to my surprise they couldn't be used together. On top of that, the "Your Page Here" gadget was configurable, but a little rough around the edges (no offense, I still thank you for the noble effort of helping everyone out). Intrigued, and with a need to put my mind on something I could accomplish in a short while I got to work on my very own Google gadget. I was rather impressed with how simple the technology was. With some reference code, firebug and docs at my disposal I created what I call "iCustomize." Hopefully I'll think of other things here and there to add to it, but for now I've kept it simple to obtain functionality as quickly as possible. The link will take you to a screenshot and link to add it to your page, below is a small image that shows the settings.


An iCustomize link is added to the tab bar which allows you to toggle the hide setting. The "Custom Tab Page" is currently only visible when the header/footer are hidden. This allows you to include gadgets on your tab which will be visible when the header/footer are visible. If the custom tab page option is disabled gadgets will always be visible. I'm happy with it for now, but I'd love to hear some comments... this blog has been barren for a little while now :).

Anyway, I'm pretty tired so I'm off, but I'll be posting sometime soon with developments from my bigger projects; I've not been slumbering ;)--See you soon,

-TheXenocide