How to save parameters like a parameterized method and then use them to convert a JSON object to a simple object of a general type?

I am trying to write a common messaging system for Delphi and .NET. The system allows you to define messages as simple objects, and message handlers are defined as anonymous methods that act on these objects.

Objects are converted to JSON and transferred between applications running on the same computer. Each application maintains a list of handlers that understand specific types of messages.

My class has a number of parameterized registration methods. Some accept one type parameter. Some take a couple of parameters in which one represents the request object and the other represents the response object. Here's what the registration of the Request / Response handler 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 this:

  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 the 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 is a better way to do this, but that was the only way I could think of saving multiple unrelated types in one collection.

It all works fine. The problem is getting a request message. C # code for processing request messages is as follows:

 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 above code, RequestType is of type Type .

But for life, I can’t come up with the equivalent of Delphi. I get to attempt to deserialize the request. Download, and I'm stuck on how to pass a JSON type parser to convert the payload. I tried various ways to store TRequest and TResponse in the RequestType and ResponseType TRequestHandler : TTypeInfo , TRTTIType and currently TClass . But nothing seems useful to me to switch to TJson.JsonToObject . It has a common overload that takes a type parameter for a return type, but apparently you cannot use TClass as a type parameter.

+7
json generics rtti delphi delphi-xe7
source share
1 answer

You cannot use TJson.JsonToObject<T> , as at the time of calling this, you do not have a common T. Look at the code of this method and you will see that T is passed to TJSONUnMarshal.CreateObject . Therefore, in your case, you must save the TClass from TRequest and TResponse and write your own version of TJson.JsonToObject , which receives a TClass .

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

+2
source share

All Articles