C#: Determine Type for (De-)Serialization
i have a little problem implementing some serialization/deserialization logic.
I have several classes that each take a different type of Request object, all implementing a common interface and inheriting from a default implementation:
This is how i think it should be:
Requests
interface IRequest
{
public String Action {get;set;}
}
class DefaultRequest : IRequest
{
public String Action {get;set;}
}
class LoginRequest : DefaultRequest
{
public String User {get;set;}
public String Pass {get;set;}
}
Handlers
interface IHandler<T>
{
public Type GetRequestType();
public IResponse HandleRequest(IModel model, T request);
}
class DefaultHandler<T> : IHandler<T> // Used as fallback if the handler cannot be determined
{
public Type GetRequestType()
{
return /* ....... how to get the Type of T? ((new T()).GetType()) ? .......... */
}
public IResponse HandleRequest(IModel model, T request)
{
/* ... */
}
}
class LoginHandler : DefaultHandler<LoginRequest>
{
public IResponse HandleRequest(IModel mode, LoginRequest request)
{
}
}
Calling
class Controller
{
public ProcessRequest(String action, String serializedRequest)
{
IHandler handler = GetHandlerForAction(action);
IRequest request = serialize开发者_如何转开发r.Deserialize<handler.GetRequestType()>(serializedRequest);
handler(this.Model, request);
}
}
Is what i think of even possible?
My current Solution is that each handler gets the serialized String and is itself responsible for deserialization. This is not a good solution as it contains duplicate code, the beginning of each HandleRequest method looks the same (FooRequest request = Deserialize(serializedRequest); + try/catch and other Error Handling on failed deserialization).
Embedding type information into the serialized Data is not possible and not intended.
Thanks for any Hints.
I may have completely misunderstood the question, but I'm just looking at the sample code and comments here...
public Type GetRequestType()
{
return /* ....... how to get the Type of T? ((new T()).GetType()) ? */
}
Are you really just trying to get the runtime type of the T
type parameter? If so, then just use typeof
.
public Type GetRequestType()
{
return typeof(T);
}
Mind you, I'm looking later at this other code:
class Controller
{
public ProcessRequest(String action, String serializedRequest)
{
IHandler handler = GetHandlerForAction(action);
IRequest request =
serializer.Deserialize<handler.GetRequestType()>(serializedRequest);
handler(this.Model, request);
}
}
You can't do this. You can't just stick a Type
in there as a generic type parameter, it won't compile. If you have an actual runtime Type
instance that you need to use as a generic parameter, then the only way to do it is with reflection:
Type serializerDef = typeof(MySerializer<>);
Type serializerType = serializerDef.MakeGenericType(requestType);
MethodInfo method = serializerType.GetMethod("Deserialize",
BindingFlags.Instance | BindingFlags.Public);
IRequest request = (IRequest)method.Invoke(serializer, serializedRequest);
It's pretty ugly, but that's the way it is when you try to mix generic types with reflection.
Oh, and this assumes that the "serializer" itself is a generic type; if you're trying to invoke a generic method on a non-generic type, as the original code suggests, then this becomes a lot more cumbersome.
精彩评论