Delphi generics EConversionError cannot instantiate type

I would like to deserialize data from an JSON string response into a class with Delphi - Is there a way to do it in Delphi with generics so I can define a POCO class for every different type of class response - within the Data property of a default Response class? I have better knowledge in C# and have accomplished it there with JavaScriptSerializer Deserialize method, like this:

public Response<T> Get<T>(string methodUrl) where T: class
...
 var _json_serializer = new JavaScriptSerializer();
 _response = _json_serializer.Deserialize<Response<T>>(api_response);
...

public class Response
{
    public bool Success { get; set; }
    public string ErrorMessage { get; set; }
}    

public class Response<T> : Response
{
    public T Data;
    public Response()
    {
        Data = default(T);
        Success = false;
        ErrorMessage = Settings.Default.errString;
    }
}

I can then call it like so:

response = _webapi.Get<GetTestClass>(url_userinfo + sUserName);

internal class GetTestClass
{
    public string DomainName { get; set; }
    public int Code { get; set; }
}

Is there a way to do this in Delphi? I have implemented a GET method in Delphi10.1 from a Web API service with the function GetUrlContent - I get a valid string response. So I tried this, it compiled but I got an error when it tried to fill the class:

uses PPUserInfoDetails, APIRootClass;
var answer_class: TRootClass<TPPUserInfoDetails>;
    Test_APIGet: string;
...
Test_APIGet := GetUrlContent(url_userinfo + sUserName);    
answer_class:= TRootClass<TPPUserInfoDetails>.FromJsonString(Test_APIGet);
...
unit PPUserInfoDetails;
interface
type

TDataClass = class
private
  FDisplayName: String;
  FCode: Integer;
  FRights: TArray<Integer>;
public
  property DisplayName: String read FDisplayName write FDisplayName;
  property Code: Integer read FCode write FCode;
  property Rights: TArray<Integer> read FRights write FRights;
end;
implementation
end.

unit APIRootClass;
interface
uses Rest.Json , sysutils;
type

TRootClass<T> = class
private
  FData: T;
  FErrorMessage: String;
  FSuccess: Boolean;
public
  property Data: T read FData write FData;
  property ErrorMessage: String read FErrorMessage write FErrorMessage;
  property Success: Boolean read FSuccess write FSuccess;
  constructor Create;
  destructor Destroy; override;
  function ToJsonString: string;
  class function FromJsonString(AJsonString: string): TRootClass<T>;
end;

implementation

constructor TRootClass<T>.Create;
begin
  inherited;
  FData := Default(T);
end;

destructor TRootClass<T>.Destroy;
begin
  freeandnil(FData);
  inherited;
end;

function TRootClass<T>.ToJsonString: string;
begin
  result := TJson.ObjectToJsonString(self);
end;

class function TRootClass<T>.FromJsonString(AJsonString: string): TRootClass<T>;
begin
  result := TJson.JsonToObject<TRootClass<T>>(AJsonString)
end;

I get the error: Project Test.exe raised exception class EConversionError with message 'Internal: Cannot instantiate type APIRootClass.TRootClass'

I am able to deserialize the data into a specific format class when I define the class without generics like this in my APINoGenerics unit:

uses APINoGenerics;
var answer_class: TRootClass;
...
Test_APIGet := GetUrlContent(url_userinfo + sUserName);
answer_class := TRootClass.FromJsonString(Test_APIGet);
...
unit APINoGenerics;
interface
uses Rest.Json;
type

TDataClass = class
private
  FDisplayName: String;
  FCode: Integer;
  FRights: TArray<Integer>;
public
  property DisplayName: String read FDisplayName write FDisplayName;
  property Code: Integer read FCode write FCode;
  property Rights: TArray<Integer> read FRights write FRights;
end;

TRootClass = class
private
  FData: TDataClass;
  FErrorMessage: String;
  FSuccess: Boolean;
public
  property Data: TDataClass read FData write FData;
  property ErrorMessage: String read FErrorMessage write FErrorMessage;
  property Success: Boolean read FSuccess write FSuccess;
  constructor Create;
  destructor Destroy; override;
  function ToJsonString: string;
  class function FromJsonString(AJsonString: string): TRootClass;
end;

implementation

constructor TRootClass.Create;
begin
  inherited;
  FData := TDataClass.Create();
end;

destructor TRootClass.Destroy;
begin
  FData.free;
  inherited;
end;

function TRootClass.ToJsonString: string;
begin
  result := TJson.ObjectToJsonString(self);
end;

class function TRootClass.FromJsonString(AJsonString: string): TRootClass;
begin
  result := TJson.JsonToObject<TRootClass>(AJsonString)
end;

I would like to be able to this with generics in Delphi - so I would just like to know if it's possible and how? I tried to search for an answer, but have mostly come across answers that generics can't function like this in Delphi so I post this since I haven't seen this type of question.

链接地址: http://www.djcxy.com/p/91108.html

上一篇: 如何在Google Chrome中进行调试时终止脚本执行?

下一篇: Delphi泛型EConversionError不能实例化类型