I have a stream onto which serialized objects representing messages are dumped periodically. The objects are one of a very limited number of types, and other than the actual sequence of bytes that arrives, I have no way of knowing what type of message it is.
I would like to simply try to deserialize it as an object of a particular type, and if an exception is thrown, try again with the next type.
I have an interface that looks like this:
public interface IMessageHandler<T> where T : class, IMessage {
T Handle(string message);
}
// elsewhere:
// (These are all xsd.exe-generated classes from an XML schema.)
public class AppleMessage : IMessage { ... }
public class BananaMessage : IMessage { ... }
public class CoconutMessage : IMessage { ... }
Then I wrote a GenericHandler<T>
that looks like this:
public class GenericHandler<T> : IMessageHandler<T> where T: class, IMessage {
public class MessageHandler : IMessageHandler {
T IMessageHandler.Handle(string message) {
T result = default(T);
try {
// This utility method tries to deserialize the object with an
// XmlSerializer as if it were an object of type T.
result = Utils.SerializationHelper.Deserialize<T>(message);
} catch (InvalidCastException e) {
result = default(T);
}
return result;
}
}
}
Using my GenericHandler<T>
(or something similar to it), I'd now like to populate a collection with handlers that each handle a different IMessage
(the Apple*
, Banana*
, and Coconut*
classes in my example). Then I want to invoke each handler's Handle
method on a particular message to see if it can be deserialized. If I get a null result, move onto the next handler; otherwise, the message has been deserialized.
That looks something like this:
I wound up doing something like this:
public object Process(string message) {
var handlers = new ArrayList {
new MessageHandler<AppleMessage>(),
new MessageHandler<BananaMessage>(),
new MessageHandler<CoconutMessage>(),
}
foreach (IMessageHandler<IMessage> h in handlers) {
var result = h.Handle(message);
// Message successfully handled! Return the result.
if (result != null) { return result; }
}
// Couldn't handle the message; return null.
return null;
}
I'm pretty sure this won't work because of covariance restrictions, however, since an IMessageHandler<AppleMessage>
is not an IMessageHandler<IMessage>
, even though an AppleMessage
is an IMessage
. Is there a different way to do this?
Additionally, is there a better way to deserialize data of unknown (but restricted) type?