行动词典代表
我有对象XML序列化消息进入一个名为MessageRouter的类。 XML包含它序列化的类型名称,我需要能够根据运行时之前未知的类型调用不同的委托方法 。 我在仿制药方面并不是非常强大,所以希望这对某些人有意义……
我希望MessageRouter提供一个RegisterDelegateForType方法,如下所示:
myMessageRouter.RegisterDelegateForType(new Action(myActionHandler));
然后将类型或类型的字符串表示forms存储在字典中,如下所示:
Dictionary<Type, Action> registeredDelegates;
这样,我可以执行类似下面的伪代码,调用类型的已分配委托并传递反序列化的对象:
Type xmlSerializedType = TypeFromXmlString(incomingXml); object deserializedObject = DeserializeObjectFromXml(xmlSerializedType, incomingXml); // then invoke the action and pass in the deserialized object registeredDelegates[xmlSerializedType](deserializedObject);
所以我的问题是:
- 如何定义一个可以包含
Type
作为键和一个通用Action
作为值的Dictionary,并使用RegisterDelegateForType方法填充字典? - 如果那是不可能的,那么最好的方法是什么?
你不能按照描述这样做,原因很明显 – 即使以某种方式允许,你的例子中的最后一行代码(检索委托然后调用它的那一行)也是非类型安全的,因为你正在调用一个Action
– 期望T
作为参数 – 然后传递deserializedObject
,它是object
类型。 如果没有演员表单,它将无法在普通代码中工作,为什么您希望能够规避您的案例的类型检查?
在最简单的情况下,您可以执行以下操作:
Dictionary registeredDelegates; ... registeredDelegates[xmlSerializedType].DynamicInvoke(deserializedObject);
当然,这将允许某人添加一个委托,该委托对字典采用多于或少于一个参数,并且您只能在运行时找到DynamicInvoke
调用。 但是实际上没有任何方法可以定义一个“任何委托,但只有1个参数”的类型。 一个更好的选择可能是:
Dictionary> registeredDelegates
然后注册这样的类型:
myMessageRouter.RegisterDelegateForType( o => myActionHandler((MySerializableType)o) );
上面的代码片段使用的是C#3.0 lambdas,但你可以使用C#2.0匿名委托来做同样的事情 – 如果稍微冗长一点。 现在你不需要使用DynamicInvoke
– lambda本身将进行适当的转换。
最后,您可以将lambda创建封装到RegisterDelegateForType
本身,方法是将其设置为generics。 例如:
private Dictionary> registeredDelegates; void RegisterDelegateForType(Action d) { registeredDelegates.Add(typeof(T), o => d((T)o)); }
而现在呼叫者可以这样做:
RegisterDelegateForType(myHandler)
因此,它对您的客户来说是完全类型安全的。 当然,您仍然有责任正确地做到这一点(即将正确类型的对象传递给您从字典中检索的委托)。
我不确定这完全回答了你的问题,但是我写的这个课程将完成你想要的。 我无法判断你是否希望你的Action委托采用一个类型化的对象,但是在你的伪代码中,你传递一个“对象”来反序列化,所以我相应地编写了我的类,因此它不使用generics:
public delegate void Action(object o); public class DelegateDictionary { private IDictionary _dictionary = new Hashtable(); public void Register(Action action) { _dictionary[typeof(T)] = action; } public Action Get () { return (Action)_dictionary[typeof(T)]; } public static void MyFunc(object o) { Console.WriteLine(o.ToString()); } public static void Run() { var dictionary = new DelegateDictionary(); dictionary.Register(MyFunc); // Can be converted to an indexer so that you can use []'s var stringDelegate = dictionary.Get (); stringDelegate("Hello World"); } }
我相信这会实现你想要的。