2010-05-10 25 views
1

我有一个小问题实现一些序列化/反序列化逻辑。C#:确定类型(去)序列化

我有几个班,每个需要不同类型的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和失败反序列化的其他错误处理)。

将类型信息嵌入到序列化数据中是不可能的,也不是预期的。

感谢您的任何提示。

回答

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

这是非常丑陋的,但是这事情是这样的,当你尝试混合泛型类型和反射。

呵呵,这里假定“串行器”本身是一个泛型类型;如果您试图调用方法非通用类型,如原始代码所示,那么这会变得非常麻烦。

+0

这是解决方案的一部分,并帮助很多(尽管我现在感到很蠢,因为我知道typeof(),但某种程度上没有记住它),但我仍然在调用部分有问题。无论如何,感谢您的帮助,我们会继续向这个方向发展。 – dbemerlin 2010-05-10 19:29:58

+1

再次感谢,看起来我不得不寻找另一种方式,因为我试图避免反射,因为它通常会伤害可读性和可维护性很多,这是我真正关心的事情。 – dbemerlin 2010-05-10 19:37:11