开发者

C#: Determine Type for (De-)Serialization

开发者 https://www.devze.com 2022-12-30 00:32 出处:网络
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 inheri

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消