I have object XML serialized messages coming into a class called MessageRouter. The XML contains the Type name it it was serialized from, a
You cannot do this as described, for quite obvious reasons - even if somehow allowed, the last line of code in your example (the one which retrieves a delegate and then calls it) would be non-typesafe, as you're calling an Action
- which expects T
as an argument - and yet passing it deserializedObject
, which is of type object
. It wouldn't work in plain code without a cast, why would you expect to be able to circumvent the type check for your case?
In the simplest case, you can do something like this:
Dictionary registeredDelegates;
...
registeredDelegates[xmlSerializedType].DynamicInvoke(deserializedObject);
Of course this will allow someone to add a delegate which takes more or less than one argument to the dictionary, and you'll only find out at DynamicInvoke
call, at run-time. But there isn't really any way to define a type which says "any delegate, but with 1 argument only". A better option might be this:
Dictionary> registeredDelegates
and then registering types like this:
myMessageRouter.RegisterDelegateForType(
o => myActionHandler((MySerializableType)o)
);
The above snippet uses C# 3.0 lambdas, but you can do the same - if slightly more verbose - with C# 2.0 anonymous delegates. Now you don't need to use DynamicInvoke
- the lambda itself will do the proper cast.
Finally, you can encapsulate the lambda creation into RegisterDelegateForType
itself by making it generic. For example:
private Dictionary> registeredDelegates;
void RegisterDelegateForType(Action d)
{
registeredDelegates.Add(typeof(T), o => d((T)o));
}
And now the callers can just do:
RegisterDelegateForType(myHandler)
So it's completely typesafe for your clients. Of course, you're still responsible for doing it right (i.e. passing an object of the correct type to the delegate you retrieve from the dictionary).