问题描述
我使用 RTTI (SuperObject) 将 JSON 转换为对象:
class function RecordJson.Json2Record<T>(const obj: ISuperObject): T;
var
ctx: TSuperRttiContext;
begin
ctx := TSuperRttiContext.Create;
try
Result := ctx.AsType<T>(obj);
finally
ctx.Free;
end;
end;
我使用这种方式并且有效:
if aSo.o['tdistanceBhTopConv'] <> nil then
Result := RecordJson.Json2Record<tdistanceBhTopConv>(aSo.o['tdistanceBhTopConv']);
但是我有很多课程。所以我创建了一个TDictionary
来记录字符串和类的关系,现在我想使用以下代码:
FClassDic: TDictionary<string,TClass>;
FClassDic.Add('tdistanceValTopConv',tdistanceValTopConv);
FClassDic.Add('tdistanceBhTopConv',tdistanceBhTopConv);
FClassDic.Add('TLbXsConv',TLbXsConv);
FClassDic.Add('TConcreteConv',TConcreteConv);
for Key in FClassDic.Keys do
if aSo.o[Key] <> nil then
begin
Result := RecordJson.Json2Record<FClassDic.Items[Key]>(aSo.o[Key]);
end;
但它无法编译:
E2250 没有可以使用这些参数调用的“Json2Record”的重载版本
我知道这是因为 TClass
(实例类)和 T
(实例)的不同。
有什么办法可以解决这个问题吗?
解决方法
您可以尝试使用对象创建过程创建字典,但如果真的值得...
type
// Object construction function type
TCreateObjectProc = reference to function(const ctx: TSuperRttiContext; obj: ISuperObject): TObject;
// Dictionary specification
FCreateDict: TDictionary<string,TCreateObjectProc>;
然后用对象构造函数填充字典
// Dictionary initialisation
FCreateDict.Add('TDistanceValTopConv',function(const ctx: TSuperRttiContext; obj: ISuperObject): TObject
begin
Result := ctx.AsType<TDistanceValTopConv>(obj);
end);
FCreateDict.Add('TDistanceBhTopConv',function(const ctx: TSuperRttiContext; obj: ISuperObject): TObject
begin
Result := ctx.AsType<TDistanceBhTopConv>(obj);
end);
FCreateDict.Add('TLbXsConv',function(const ctx: TSuperRttiContext; obj: ISuperObject): TObject
begin
Result := ctx.AsType<TLbXsConv>(obj);
end);
FCreateDict.Add('TConcreteConv',function(const ctx: TSuperRttiContext; obj: ISuperObject): TObject
begin
Result := ctx.AsType<TConcreteConv>(obj);
end);
然后使用它
for Key in FCreateDict.Keys do
if aSo.o[Key] <> nil then
begin
ctx := TSuperRttiContext.Create;
try
Result := FCreateDict.Items[Key](ctx,aSo.o[Key]);
finally
ctx.Free;
end;
end;
当使用 Remy 的 TSerializer<T: class>
类时:
type
TSerializer<T: class> = class
public
class function Deserialize(const ctx: TSuperRttiContext; obj: ISuperObject): TObject;
end;
class function TSerializer<T>.Deserialize(const ctx: TSuperRttiContext;
obj: ISuperObject): TObject;
begin
Result := ctx.AsType<T>(obj);
end;
那么关于字典初始化的代码如下(使用Delphi 10.3编译)
FCreateDict.Add('TDistanceValTopConv',TSerializer<TDistanceValTopConv>.Deserialize);
FCreateDict.Add('TDistanceBhTopConv',TSerializer<TDistanceBhTopConv>.Deserialize);
FCreateDict.Add('TLbXsConv',TSerializer<TLbXsConv>.Deserialize);
FCreateDict.Add('TConcreteConv',TSerializer<TConcreteConv>.Deserialize);