【发布时间】:2014-07-29 14:07:58
【问题描述】:
我定义了一个只包含字符串作为属性的类,我需要根据其值获取属性名称,如下例所示。在示例中只有 3 个属性,在现实生活中的类中几乎有 1000 个。问题是这个类被大量使用,我想知道是否可以更快地通过其值获取属性名称。
unit Unit5;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs,RTTI, StdCtrls, Diagnostics;
type
TConstDBElem = class
public
CCFN_1 : String;
CCFN_2 : String;
CCFN_3 : String;
constructor Create;
end;
TForm5 = class(TForm)
Memo1: TMemo;
Button1: TButton;
procedure Button1Click(Sender: TObject);
end;
var
Form5: TForm5;
Obj: TConstDBElem;
implementation
{$R *.dfm}
procedure TForm5.Button1Click(Sender: TObject);
var iPos:Integer;
timer:TStopwatch;
Function GetName(const DBElemInstance : TConstDBElem; valueName: string) : string;
var
vrttiContext: TRttiContext;
vrttiField : TRttiField;
vType : TRttiType;
begin
vType := vrttiContext.GetType(TConstDBElem);
for vrttiField in vType.GetFields do
if (vrttiField.GetValue(DBElemInstance).ToString = valueName) then
begin
result := vrttiField.Name;
end;
end;
begin
timer := TStopwatch.Create;
timer.Start;
Memo1.Lines.Clear;
for iPos := 0 to 100000 do
GetName(Obj,'TEST3');
timer.Stop;
Memo1.Lines.Add(FloatToStr(timer.Elapsed.TotalSeconds));
end;
constructor TConstDBElem.Create;
begin
CCFN_1 := 'TEST1';
CCFN_2 := 'TEST2';
CCFN_3 := 'TEST3' ;
end;
initialization
Obj := TConstDBElem.Create;
finalization
Obj.Free;
end.
是的,我知道这是一个非常糟糕的设计,不应该这样做。是否有任何选项可以加快搜索速度?
【问题讨论】:
-
字段的值在运行时会改变吗?如果是这样,你怎么能比遍历所有字段寻找具有所需名称的字段做得更好?我会建议一个不同的设计,但看起来课程已经设计好了,为时已晚。
-
是什么让您决定在这三个参考资料上致电
Free?在许多层面上这样做是错误的。vrttiContext不需要。也不是对TRttiContext.Create的调用。vType和vrttiField完全错误。不要破坏它们。vrttiField是一个循环变量。您在循环结束时调用Free的任何值。对于 for in 循环,这可能已经很好地定义了。我什至不确定。不管怎样都是假的。最后,尝试是在错误的地方。您可以轻松地在未初始化的变量上调用Free。 -
不,这些值在运行时不会更改。是的,改设计不合适……
-
顺便说一句,一个拥有近 1000 个属性/字段的类一开始看起来并不是一个好主意。
-
如果所有属性都是字符串,那么您可以使用
TStringList及其名称/值对。那么你只需要一件事,而不是成千上万。这就是TStringList的Values属性的设计目的。顺便说一句,看看你的代码,你没有任何“属性”,只有“字段”。