Login | Register   
LinkedIn
Google+
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


advertisement
 

Generic Dictionaries: Hidden Treasure of System.Collections.Generic : Page 3

Generic dictionaries simplify common tasks, such as coordinating selection between a TreeView and a ListView—but their capabilities extend far beyond that, once you realize you can use DynamicInvoke() to execute delegates stored in the dictionary.


advertisement
Introducing Dynamic Code Dictionaries
Let's take a look at a more radical use of generic dictionaries.

Suppose that, instead of the generic dictionary you've seen so far, you were to create a generic dictionary of the form:

Dictionary ControlDictionary<Control, ProcedureBody>

In the ControlDictionary type shown above, each key is an object reference to a Control type, and each value is executable C# code. Whoa! Did you just say, "executable?" Ah, yes, I did.

At this point, you're heading "down the rabbit-hole" into the interesting world of late-binding, because you could alter the value associated with a key at any time, plugging-in a new piece of executable code.
The code isn't directly executable, though; you execute it "indirectly" after retrieving it from the ControlDictionary using a control in an application as a key. At this point, you're heading "down the rabbit-hole" into the interesting world of late-binding, because you could alter the value associated with a key at any time, plugging-in a new piece of executable code.

To accomplish this you set the value associated with any given key to a Delegate instance bound to a MethodBody (executable code). You can then execute the bound method using DynamicInvoke(). Whether 'tis better to use Invoke rather than DynamicInvoke is left for you to investigate/debate/flame.

While you're "downstairs with Alice" in late-binding land, it's worth showing off how to use anonymous methods bound to one (and only one) Delegate declaration. The code below shows how to do that:

private delegate void theMethod(); private Dictionary<Control, theMethod> controlMethodDictionary; private void testForm_Load(object sender, EventArgs e) { controlMethodDictionary = new Dictionary<Control, theMethod>(); controlMethodDictionary.Add(tv1, delegate { nodeDictionary[tv1.SelectedNode].Selected = true; } ); controlMethodDictionary.Add(lv1, delegate { tv1.SelectedNode = LVIDictionary[lv1.SelectedItems[0]]; } ); }

The example reuses the TreeView and ListView controls and generic dictionary classes from the previous example, but this time you have a dictionary object containing a single key that's either a ListView or TreeView control on the form. The value associated with that key is a delegate to a procedure that keeps the TreeView and ListView selections synchronized.

The "surprise" may be that you can get away with using one delegate named theMethod as the type identifier in the definition of a generic dictionary.
You can see that the above code shows how to use anonymous methods bound to nameless delegates. Surprised? The "surprise" may be that you can get away with using one delegate named theMethod as the type identifier in the definition of a generic dictionary, but just remind yourself, as I had to, that a delegate is a first-class type!

Now all you have to do is invoke those methods in the AfterSelect event for the TreeView and the ItemActivate for the ListView, which is so easy. Note that using DynamicInvoke does not require a reference to the Reflection library in your code header.



private void tv1_AfterSelect(object sender, TreeViewEventArgs e) { controlMethodDictionary[tv1].DynamicInvoke(); } private void lv1_ItemActivate(object sender, EventArgs e) { controlMethodDictionary[lv1].DynamicInvoke(); }

This article has only scratched (tickled?) the surface of one aspect of the functionality in generics in .NET 2.0. Consider the possibilities opened up by your freedom to derive/extend from custom or built-in generic types, such as adding virtual or abstract methods to your extended/derived types and using generic interfaces and delegates.

But here's a reality check: Should you use late-binding? Should you stuff anonymous methods into values in a generic dictionary, and then execute them later? I'm not going to attempt to answer that question. My goal here is to broaden your awareness of what's possible with generic dictionaries, so you can add them to your arsenal of Ninja tools. When and where you use late-binding, in what context, and what specific techniques you use (or don't use) with generic dictionaries is between you and Donald Knuth, thanks.



Bill Woodruff took up programming at age 40, worked on the PostScript language, at Cricket, Emerald City, and at Adobe on the Illustrator 3.2 and 5.0 teams, and the Acrobat prototype. He now works with .NET 2.0 and C#, and enjoys playing with the WPF/WinFX technologies. He currently lives in Chiang Mai, Thailand.
Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Sitemap