记录的通用助手
Generic helper for record
目前我有很多这样的辅助方法的记录:
TRec1 = packed record
S1: string;
S2: string;
procedure FromJSON(const AJSON: string);
function ToJSON: string;
end;
procedure TRec1.FromJSON(const AJSON: string);
begin
RecordLoadJSON(Self, StringToUTF8(AJSON), TypeInfo(TRec1));
end;
function TRec1.ToJSON: string;
begin
Result := UTF8ToString(RecordSaveJSON(Self, TypeInfo(TRec1)));
end;
TRec2 = packed record
S1: string;
I1: string;
procedure FromJSON(const AJSON: string);
function ToJSON: string;
end;
procedure TRec2.FromJSON(const AJSON: string);
begin
RecordLoadJSON(Self, StringToUTF8(AJSON), TypeInfo(TRec2));
end;
function TRec2.ToJSON: string;
begin
Result := UTF8ToString(RecordSaveJSON(Self, TypeInfo(TRec2)));
end;
如您所见,所有记录都包含相同的 ToJSON 和 FromJSON 方法。
此方法包含完全相同的代码,除了 TypeInfo()
有什么方法可以为此使用泛型并且不为每个记录声明此方法?
记录或classes?
尽管 Delphi 支持方法,但记录仍然是第二 class 公民,因为不支持记录继承。
类 拥有记录的所有功能以及全套 OOP 功能,因此它们通常是更好的选择。但是,您需要处理需要在非 ARC 平台上手动管理 classes 的创建和销毁的引用语义,以及具有自动清理功能的记录的无忧值语义。
非泛型解决方案(使用 class)
将字符串容器声明为 class 并使用继承。
TRec1 = class(TPersistent)
S1: string;
S2: string;
procedure FromJSON(const AJSON: string);
function ToJSON: string;
end;
TRec2 = class(TRec1)
end;
procedure TRec1.FromJSON(const AJSON: string);
begin
RecordLoadJSON(Self, StringToUTF8(AJSON), Self.ClassInfo);
end;
function TRec1.ToJSON: string;
begin
Result := UTF8ToString(RecordSaveJSON(Self, Self.ClassInfo));
end;
所有从 TPersistent
继承的 classes 都有 RTTI,因此 self.classinfo
有效。
您可能需要根据需要修改 RecordSaveJSON
调用。
泛型解决方案
如果您为您的单元 {$M+}
启用了 RTTI 并且您必须使用记录,只需使用记录之外的方法并将记录类型作为通用参数提供。
TRec1 = record
data: typex;
....
end;
TDoJSONThings = record //helper record for any and all types with RTTI.
procedure FromJSON<T:record>(var Data: T; const JSON: string); static;
function ToJSON<T:record>(const [ref] Data: T): string; static;
end;
procedure TDOJSONThings.FromJSON<T>(var Data: T; const JSON: string); static;
var
pt: PTypeInfo;
begin
pt:= TypeInfo(T);
RecordLoadJSON(Data, StringToUTF8(AJSON), pt);
end;
function TDOJSONThings.ToJSON<T:record>(const [ref] Data: T): string; static;
var
pt: PTypeInfo;
begin
pt:= TypeInfo(T);
Result:= UTF8ToString(RecordSaveJSON(Data, pt));
end;
备注
使用 record helper
(如 THelper = record helper for TRec1
)将不起作用,因为这仅适用于 TRec1
并且很遗憾,记录不支持继承。
最好使用独立方法,但 Delphi 不允许不属于记录或 class 一部分的泛型方法。
哦,请放弃 1970 年代的 packed record
风格构造。它没有任何作用,只是通过错位让你的代码变慢。
目前我有很多这样的辅助方法的记录:
TRec1 = packed record
S1: string;
S2: string;
procedure FromJSON(const AJSON: string);
function ToJSON: string;
end;
procedure TRec1.FromJSON(const AJSON: string);
begin
RecordLoadJSON(Self, StringToUTF8(AJSON), TypeInfo(TRec1));
end;
function TRec1.ToJSON: string;
begin
Result := UTF8ToString(RecordSaveJSON(Self, TypeInfo(TRec1)));
end;
TRec2 = packed record
S1: string;
I1: string;
procedure FromJSON(const AJSON: string);
function ToJSON: string;
end;
procedure TRec2.FromJSON(const AJSON: string);
begin
RecordLoadJSON(Self, StringToUTF8(AJSON), TypeInfo(TRec2));
end;
function TRec2.ToJSON: string;
begin
Result := UTF8ToString(RecordSaveJSON(Self, TypeInfo(TRec2)));
end;
如您所见,所有记录都包含相同的 ToJSON 和 FromJSON 方法。 此方法包含完全相同的代码,除了 TypeInfo()
有什么方法可以为此使用泛型并且不为每个记录声明此方法?
记录或classes?
尽管 Delphi 支持方法,但记录仍然是第二 class 公民,因为不支持记录继承。
类 拥有记录的所有功能以及全套 OOP 功能,因此它们通常是更好的选择。但是,您需要处理需要在非 ARC 平台上手动管理 classes 的创建和销毁的引用语义,以及具有自动清理功能的记录的无忧值语义。
非泛型解决方案(使用 class)
将字符串容器声明为 class 并使用继承。
TRec1 = class(TPersistent)
S1: string;
S2: string;
procedure FromJSON(const AJSON: string);
function ToJSON: string;
end;
TRec2 = class(TRec1)
end;
procedure TRec1.FromJSON(const AJSON: string);
begin
RecordLoadJSON(Self, StringToUTF8(AJSON), Self.ClassInfo);
end;
function TRec1.ToJSON: string;
begin
Result := UTF8ToString(RecordSaveJSON(Self, Self.ClassInfo));
end;
所有从 TPersistent
继承的 classes 都有 RTTI,因此 self.classinfo
有效。
您可能需要根据需要修改 RecordSaveJSON
调用。
泛型解决方案
如果您为您的单元 {$M+}
启用了 RTTI 并且您必须使用记录,只需使用记录之外的方法并将记录类型作为通用参数提供。
TRec1 = record
data: typex;
....
end;
TDoJSONThings = record //helper record for any and all types with RTTI.
procedure FromJSON<T:record>(var Data: T; const JSON: string); static;
function ToJSON<T:record>(const [ref] Data: T): string; static;
end;
procedure TDOJSONThings.FromJSON<T>(var Data: T; const JSON: string); static;
var
pt: PTypeInfo;
begin
pt:= TypeInfo(T);
RecordLoadJSON(Data, StringToUTF8(AJSON), pt);
end;
function TDOJSONThings.ToJSON<T:record>(const [ref] Data: T): string; static;
var
pt: PTypeInfo;
begin
pt:= TypeInfo(T);
Result:= UTF8ToString(RecordSaveJSON(Data, pt));
end;
备注
使用 record helper
(如 THelper = record helper for TRec1
)将不起作用,因为这仅适用于 TRec1
并且很遗憾,记录不支持继承。
最好使用独立方法,但 Delphi 不允许不属于记录或 class 一部分的泛型方法。
哦,请放弃 1970 年代的 packed record
风格构造。它没有任何作用,只是通过错位让你的代码变慢。