C#:确定(De-)序列化的类型

时间:2010-05-10 19:12:39

标签: c# serialization type-conversion

我在实现一些序列化/反序列化逻辑时遇到了一些问题。

我有几个类,每个类都采用不同类型的Request对象,所有类都实现了一个公共接口并继承了默认实现:

我认为这应该是:

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;} 
}

处理程序

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)
  {
  }
}

调用

class Controller
{
  public ProcessRequest(String action, String serializedRequest)
  {
    IHandler handler = GetHandlerForAction(action);
    IRequest request = serializer.Deserialize<handler.GetRequestType()>(serializedRequest);
    handler(this.Model, request);
  }
}

我认为甚至可能吗?

我目前的解决方案是每个处理程序获取序列化的字符串,并且自己负责反序列化。这不是一个好的解决方案,因为它包含重复的代码,每个HandleRequest方法的开头看起来都一样(FooRequest request = Deserialize(serializedRequest); + try / catch和其他错误处理失败的反序列化)。

无法将预期类型信息嵌入到序列化数据中。

感谢任何提示。

1 个答案:

答案 0 :(得分:2)

我可能完全误解了这个问题,但我只是在看这里的示例代码和评论......

public Type GetRequestType()
{
    return /* ....... how to get the Type of T? ((new T()).GetType()) ? */
}

您真的只是想获取T类型参数的运行时类型吗?如果是这样,那么只需使用typeof

public Type GetRequestType()
{
    return typeof(T);
}

请注意,我稍后会查看其他代码:

class Controller
{
    public ProcessRequest(String action, String serializedRequest)
    {
        IHandler handler = GetHandlerForAction(action);
        IRequest request = 
            serializer.Deserialize<handler.GetRequestType()>(serializedRequest);
        handler(this.Model, request);
    }
}

你不能这样做。你不能只将Type作为泛型类型参数粘贴在那里,它不会编译。如果您有一个实际的运行时Type实例,您需要将其用作通用参数,那么唯一的方法是使用反射:

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);

这很丑陋,但是当你尝试将泛型类型与反射混合时就是这样。

哦,这假设“序列化器”本身是一般类型;如果您尝试在非泛型类型上调用泛型方法,正如原始代码所示,那么这会变得更加麻烦。