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>();
nodeDictionary[tv1.SelectedNode].Selected = true;
tv1.SelectedNode = LVIDictionary[lv1.SelectedItems];
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
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
require a reference to the Reflection library in your code header.
private void tv1_AfterSelect(object sender, TreeViewEventArgs e)
private void lv1_ItemActivate(object sender, EventArgs e)
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.