如何存储参数化方法的类型参数,然后使用它们将JSON对象转换为泛型类型的普通对象?

时间:2021-12-19 00:42:06

I am attempting to write a generic messaging passing system for Delphi and .NET. The system allows messages to be defined as plain objects and message handlers are defined as anonymous methods that act on those objects.

我正在尝试为Delphi和.NET编写通用的消息传递系统。系统允许将消息定义为普通对象,并将消息处理程序定义为对这些对象起作用的匿名方法。

The objects are converted to JSON and passed between applications running on the same machine. Each application maintains a list of handlers that understand specific message types.

对象将转换为JSON,并在同一台计算机上运行的应用程序之间传递。每个应用程序都维护一个理解特定消息类型的处理程序列表。

My class has a number of parameterized registration methods. Some take a single type parameter. Some take a pair of parameters where one represents a request object and the other a response object. Here is what the Request/Response handler registration looks like:

我的类有许多参数化注册方法。有些采用单一类型参数。有些参数采用一对参数,其中一个表示请求对象,另一个表示响应对象。以下是请求/响应处理程序注册的内容:

procedure TTelegraph.RegisterRequestHandler<TRequest, TResponse>
  (requestTypeToHandle: string; handler: TFunc<TRequest, TResponse>);
begin
  FRequestHandlers.Add(requestTypeToHandle,
    TRequestHandler<TRequest, TResponse>.Create(handler,
    TRequest,
    TResponse));
end;

FRequestHandlers is a TDictionary<string,TRequestHandler>. The registration method is called like so:

FRequestHandlers是一个TDictionary 。注册方法如下调用: ,trequesthandler>

  FTelegraph.RegisterRequestHandler<TTestRequest, TTestResponse>('My Request', 
    function(x: TTestRequest): TTestResponse
    begin
      Result := TTestResponse.Create;
      Result.Number := x.Number;
      Result.Message := Format('Received: %s', [x.Message]);
    end);

The generic TRequestHandler<T1,T2> is a DTO that wraps the handler along with the types TRequest and TResponse. It inherits from the non-generic TRequestHandler. I'm not sure if there's a better way to go about this but it was the only way I could think of to store multiple unrelated types in a single collection.

通用TRequestHandler 是一个DTO,它将处理程序与TRequest和TResponse类型一起包装。它继承自非通用的TRequestHandler。我不确定是否有更好的方法可以解决这个问题,但这是我能想到的在单个集合中存储多个不相关类型的唯一方法。 ,t2>

This all seems to work fine. The problem is when a request message is received. The C# code to handle request messages looks like this:

这一切似乎都很好。问题是收到请求消息时。处理请求消息的C#代码如下所示:

private void ProcessRequestTelegram(Telegram request)
{
    var requestType = _RequestHandlers[request.MessageType].RequestType;
    var typedRequest = JsonConvert.DeserializeObject(request.Payload, requestType);
    var result = _RequestHandlers[request.MessageType].Handler.DynamicInvoke(typedRequest);
    var jsonPayload = JsonConvert.SerializeObject(result);
    var response = new Telegram()
    {
        Payload = jsonPayload,
        CorrelationID = request.CorrelationID,
        Template = TelegramTemplateEnum.Response,
        SenderWindowHandle = _LocalWindowHandle.ToInt32(),
        RecipientWindowHandle = _MessageRecipient.ToInt32(),
        MessageType = request.MessageType
    };
    var jsonResponse = JsonConvert.SerializeObject(response);

    var resultCode = _Messaging.SendMessage(_MessageRecipient, jsonResponse);
    CheckIfSendMessageErrorOccurred(resultCode);
}

In the code above RequestType is of the Type type.

在上面的代码中,RequestType属于Type类型。

But for the life of me I can't come up with the Delphi equivalent. I get as far as attempting to deserialize the request.Payload and I'm stuck at how to pass the JSON parser the type to convert the payload into. I've tried various ways of storing TRequest and TResponse in the RequestType and ResponseType properties of TRequestHandler: TTypeInfo, TRTTIType and currently TClass. But nothing seems to give me anything useful to pass to TJson.JsonToObject. It has a generic overload that takes a type parameter for the return type but apparently you can't use a TClass as a type parameter.

但对于我的生活,我无法想出Delphi的等价物。我试图反序列化request.Payload,我坚持如何传递JSON解析器类型转换有效负载。我已经尝试了各种方法在TRequestHandler的RequestType和ResponseType属性中存储TRequest和TResponse:TTypeInfo,TRTTIType和当前的TClass。但似乎没有任何东西可以传递给TJson.JsonToObject。它有一个泛型重载,它接受返回类型的类型参数,但显然你不能使用TClass作为类型参数。

1 个解决方案

#1


2  

You cannot use TJson.JsonToObject<T> as at the time of calling this you don't have a generic T. Look into the code of this method and you see that T is being passed to TJSONUnMarshal.CreateObject. So in your case you should store the TClass of TRequest and TResponse and write your own version of TJson.JsonToObject that gets passed a TClass.

你不能使用TJson.JsonToObject ,因为在调用它时你没有泛型T.查看这个方法的代码,你会看到T被传递给TJSONUnMarshal.CreateObject。因此,在您的情况下,您应该存储TRequest和TResponse的TClass并编写自己的TJson.JsonToObject版本,该版本将传递一个TClass。

Another way would be to create your instance first and then pass it to the non generic TJson.JsonToObject which takes the ClassType of the passed instance and passes it to TJSONUnMarshal.CreateObject.

另一种方法是先创建实例,然后将其传递给非泛型TJson.JsonToObject,它接受传递实例的ClassType并将其传递给TJSONUnMarshal.CreateObject。

#1


2  

You cannot use TJson.JsonToObject<T> as at the time of calling this you don't have a generic T. Look into the code of this method and you see that T is being passed to TJSONUnMarshal.CreateObject. So in your case you should store the TClass of TRequest and TResponse and write your own version of TJson.JsonToObject that gets passed a TClass.

你不能使用TJson.JsonToObject ,因为在调用它时你没有泛型T.查看这个方法的代码,你会看到T被传递给TJSONUnMarshal.CreateObject。因此,在您的情况下,您应该存储TRequest和TResponse的TClass并编写自己的TJson.JsonToObject版本,该版本将传递一个TClass。

Another way would be to create your instance first and then pass it to the non generic TJson.JsonToObject which takes the ClassType of the passed instance and passes it to TJSONUnMarshal.CreateObject.

另一种方法是先创建实例,然后将其传递给非泛型TJson.JsonToObject,它接受传递实例的ClassType并将其传递给TJSONUnMarshal.CreateObject。