Despite the fact that this is an old post, what stands here is the third solution.
I was worried about the general problem of creating send tables, for example. static lookup tables for non-static methods. A typical use may be in ASP.NET event handling.
We would like the syntax and initialization to be as simple as possible. If the declaration and initialization of the send table is too complex, it would be easier / safer to simply write an explicit If-then-else-if or switch expression that sends the message.
We can declare a collection of delegates very simply. Assuming some methods Method1, Method2 and the delegate type SomeDelegate for them, then we can write:
Dictionary<string, SomeDelegate> dispatchTable = new Dictionary<string, SomeDelegate> { { "Key1", Method1 } ,{ "Key2", Method2 } .... }
In this case, we initialize the delegates using the method name directly.
While this works, unfortunately, it will not work as soon as we try to make dispatchTable a static member. This is because SomeDelegate is a private delegate (associated with an instance) and therefore cannot be initialized from a static scope. This is disappointing because our required mailings are known at compile time, so ideally we should set up a static send table.
As indicated in the selected solution in this thread, you can create open delegates via CreateDelegate, but this is syntactically inconvenient and also relies on passing the method name as a string to create the delegate so that you lose compile time checking. Declaring an offset table using this syntax would be very dirty.
The extension method method is less verbose and retains compile-time checking, but it is still inconvenient compared to the syntax above.
Another (third) option is to wrap the private delegates in a binding function, which, provided that the class instance returns the desired (closed) delegate. For example, you can use Func.
Then the dispatch table is basically:
public class DispatchTable<Class, Key, Delegate> : Dictionary<Key, Func<Class, Delegate>>
Assuming some methods called EventHandler1, EventHandler2 and the delegate type for them, for example.
delegate int EventHandler(string param1, int param2);
then declaring and initializing a static distribution table of non-static elements is as simple as:
class MyDispatchTable : DispatchTable<MyClass, string, EventHandler> static MyDispatchTable dispatchTable = new MyDispatchTable { { "Event1", c => c.EventHandler1 } ,{ "Event2", c => c.EventHandler2 } };
Now the methods can be called through the distribution table taking into account the class instance, the key for the handler and the method parameters.
As an example, calling from a member function of the class itself, that is, an instance of the class = this, for the key k and parameters p1, p2, the syntax will look like this:
var result = dispatchTable[key](this)(p1, p2);
Note that this ignores appropriate error checking, for example. nonexistent keys. Error checking can be completed in the GetDelegate method in the DispatchTable class.
A complete example is given below. Note that it also includes a separate extension method for the Dictionary class to simplify the syntax for error handling.
Dictionary Extension:
static public class DictionaryExtensions { // extension method to simplify accessing a dictionary static public V GetValueOrDefault<K, V>(this Dictionary<K, V> dict, K key) { V value; dict.TryGetValue(key, out value); return value; } }
Dispatch table class:
Usage example:
public class Test { // some member functions to invoke public int EventHandler1(string param1, int param2) { return 1; } public int EventHandler2(string param1, int param2) { return 2; } // Declaration for a (closed) delegate for the member functions private delegate int EventHandler(string param1, int param2); // Syntactic sugar for declaring the table private class EventDispatchTable : DispatchTable<string, Test, EventHandler> { }; // Declare dispatch table and initialize static EventDispatchTable dispatchTable = new EventDispatchTable { { "Event1", c => c.EventHandler1 } ,{ "Event2", c => c.EventHandler2 } }; // Invoke via the dispatch table public int DoDispatch(string eventName, string param1, int param2) { return dispatchTable.GetDelegate(this, eventName)(param1, param2); } }