行动词典<T>代表

Bra*_*don 6 .net c# generics

我有对象XML序列化消息进入一个名为MessageRouter的类.XML包含它从中序列化的类型名称,我需要能够根据直到运行时才知道的类型调用不同的委托方法.我在仿制药方面并不是非常强大,所以希望这对某人有意义......

我希望MessageRouter提供一个RegisterDelegateForType方法,如下所示:

myMessageRouter.RegisterDelegateForType(new Action<MySerializableType>(myActionHandler));
Run Code Online (Sandbox Code Playgroud)

然后将类型或类型的字符串表示形式存储在字典中,如下所示:

Dictionary<Type, Action<T>> registeredDelegates;
Run Code Online (Sandbox Code Playgroud)

这样,我可以执行类似下面的伪代码,调用类型的已分配委托并传递反序列化的对象:

Type xmlSerializedType = TypeFromXmlString(incomingXml);
object deserializedObject = DeserializeObjectFromXml(xmlSerializedType, incomingXml);

// then invoke the action and pass in the deserialized object
registeredDelegates[xmlSerializedType](deserializedObject);
Run Code Online (Sandbox Code Playgroud)

所以我的问题是:

  1. 如何定义一个可以包含Type键作为键和泛型Action<T>作为值的Dictionary ,并使用RegisterDelegateForType方法填充字典?
  2. 如果那是不可能的,那么最好的方法是什么?

Pav*_*aev 23

你不能这样做,原因很明显 - 即使以某种方式允许,你的例子中的最后一行代码(检索委托然后调用它的那一行)将是非类型安全的,因为你正在调用Action<T>-期望T作为一个论点 - 然而传递它deserializedObject,这是类型object.如果没有演员表单,它将无法在普通代码中工作,为什么您希望能够绕过案例的类型检查?

在最简单的情况下,您可以执行以下操作:

Dictionary<Type, Delegate> registeredDelegates;
...
registeredDelegates[xmlSerializedType].DynamicInvoke(deserializedObject);
Run Code Online (Sandbox Code Playgroud)

当然,这将允许某人添加一个委托,该委托对字典采用多于或少于一个参数,并且您只能DynamicInvoke在运行时找到通话.但是,实际上没有任何方法可以定义一个"任何委托,但只有1个参数"的类型.一个更好的选择可能是:

Dictionary<Type, Action<object>> registeredDelegates
Run Code Online (Sandbox Code Playgroud)

然后注册这样的类型:

myMessageRouter.RegisterDelegateForType<MySerializableType>(
   o => myActionHandler((MySerializableType)o)
);
Run Code Online (Sandbox Code Playgroud)

上面的代码片段使用的是C#3.0 lambdas,但你可以使用C#2.0匿名委托来做同样的事情 - 如果稍微冗长一点.现在你不需要使用DynamicInvoke- lambda本身将进行适当的转换.

最后,您可以RegisterDelegateForType通过使lambda创建为通用来将lambda创建封装在自身中.例如:

private Dictionary<Type, Action<object>> registeredDelegates;

void RegisterDelegateForType<T>(Action<T> d)
{
    registeredDelegates.Add(typeof(T), o => d((T)o));
}
Run Code Online (Sandbox Code Playgroud)

而现在呼叫者可以这样做:

RegisterDelegateForType<MySerializableType>(myHandler)
Run Code Online (Sandbox Code Playgroud)

所以它对您的客户来说是完全类型安全的.当然,您仍然有责任正确地做到这一点(即将正确类型的对象传递给您从字典中检索的委托).