C #: определить тип для (де-) сериализации - PullRequest
1 голос
/ 10 мая 2010

У меня небольшая проблема с реализацией логики сериализации / десериализации.

У меня есть несколько классов, каждый из которых принимает свой тип объекта 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 = Deserialize (serializedRequest); + try / catch и другая обработка ошибок при неудачной десериализации).

Внедрение информации о типе в сериализованные данные невозможно и не предназначено.

Спасибо за любые подсказки.

1 Ответ

2 голосов
/ 10 мая 2010

Я, возможно, совершенно не понял вопроса, но я просто смотрю пример кода и комментарии здесь ...

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

Это довольно уродливо, но так происходит, когда вы пытаетесь смешивать универсальные типы с отражением.

О, и это предполагает, что сам "сериализатор" является универсальным типом; если вы пытаетесь вызвать универсальный метод для неуниверсального типа , как предполагает оригинальный код, то это становится намного более громоздким.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...