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