尽管这是一篇旧帖子,但是以下的第三种解决方案也许还有参考价值。
我关心的是创建分派表的通用问题,例如非静态方法的静态查找表。典型的应用可能在ASP.NET事件处理中使用。
我们希望语法和初始化尽可能简单。如果声明和初始化分派表过于复杂,那么编写显式的 If-then-else-if 或 switch 语句来执行分派可能会更简单/更安全。
我们可以非常简单地声明一个委托集合。 假设存在一些方法 Method1、Method2 和它们的委托类型 SomeDelegate,则我们可以编写:
Dictionary<string, SomeDelegate> dispatchTable = new Dictionary<string, SomeDelegate>
{
{ "Key1", Method1 }
,{ "Key2", Method2 }
....
}
在这种情况下,我们直接使用方法名来初始化委托。
虽然这样做是可行的,但是一旦我们尝试将dispatchTable设置为静态成员,它就会失败。
这是因为SomeDelegate是一个闭合委托(绑定到实例),因此无法从静态范围初始化。
这很令人沮丧,因为我们的所需调度在编译时已知,因此理想情况下,我们应该能够静态声明我们的调度表。
正如在此线程中选择的解决方案所指出的那样,您可以通过CreateDelegate创建开放式委托,但这在语法上很笨拙,并且还依赖于将方法名作为字符串传递以创建委托,因此会失去编译时检查。使用此语法声明调度表将非常混乱。
扩展方法技术比上述语法更简洁,并保留了编译时检查,但与之相比仍然很笨拙。
另一个(第三个)选项是将闭合委托包装在(绑定)函数中,该函数在给定类实例时将返回所需的(闭合)委托。例如,您可以使用Func。
然后,调度表基本上是:
public class DispatchTable<Class, Key, Delegate> : Dictionary<Key, Func<Class, Delegate>>
假设有一些名为EventHandler1、EventHandler2的方法,以及用于它们的委托类型,例如:<p>。
delegate int EventHandler(string param1, int param2);
声明并初始化一个非静态成员的静态调度表就像这样简单:
class MyDispatchTable : DispatchTable<MyClass, string, EventHandler>
static MyDispatchTable dispatchTable = new MyDispatchTable
{
{ "Event1", c => c.EventHandler1 }
,{ "Event2", c => c.EventHandler2 }
};
现在可以通过调度表,在给定类的实例、处理程序键和方法参数的情况下调用方法。
例如,如果要从类自身的成员函数即类实例=this中调用,使用键k和参数p1,p2,则语法应如下:
var result = dispatchTable[key](this)(p1, p2)
请注意,这忽略了适当的错误检查,例如不存在的键。 错误检查可以包装在DispatchTable类的GetDelegate方法中。
下面给出一个完整的示例。 请注意,它还包括一个用于Dictionary类的单独扩展方法,以简化错误处理的语法。
字典扩展:
static public class DictionaryExtensions
{
static public V GetValueOrDefault<K, V>(this Dictionary<K, V> dict, K key)
{
V value;
dict.TryGetValue(key, out value);
return value;
}
}
调度表类:
public class DispatchTable<Key, Class, Delegate> : Dictionary<Key, Func<Class, Delegate>>
{
public Delegate GetDelegate(Class c, Key k)
{
var d = GetValueOrDefault(k);
if (d == null)
{
throw new ArgumentException(String.Format("Delegate not found for key [{0}]",k));
}
return d(c);
}
};
使用示例:
public class Test
{
public int EventHandler1(string param1, int param2) { return 1; }
public int EventHandler2(string param1, int param2) { return 2; }
private delegate int EventHandler(string param1, int param2);
private class EventDispatchTable : DispatchTable<string, Test, EventHandler> { };
static EventDispatchTable dispatchTable = new EventDispatchTable
{
{ "Event1", c => c.EventHandler1 }
,{ "Event2", c => c.EventHandler2 }
};
public int DoDispatch(string eventName, string param1, int param2)
{
return dispatchTable.GetDelegate(this, eventName)(param1, param2);
}
}