我认为这应该是非常直接的,但我不知道为什么这不起作用。
我已经接管了遗留代码,并且dll中使用的一些对象变得无法管理。几个对象具有相同的过程
SetPropertyValue(propName,propValue:string);
现在,这些方法基本上是巨型if..else
语句,用于检查propName
并指定propValue
是否与对象属性匹配:
if propName='name' then
name:=propValue
else if propName='address' then
address:=propValue
等等。
每次一个对象获得一个新属性(或者一个属性类型发生变化,因此传入的value参数需要以不同的方式进行转换)时,这个方法需要更新 - 显然是一个不需要的杂务。
我选择编写一个全局方法来设置一个动态的对象属性,并且需要最少的维护。
这是我到目前为止所做的一个简短例子。有两个单元,Obj和Main - 其中Main是一个带有2个编辑框和一个按钮的VCL表单,我使用按钮点击来触发SetPropertyValue:
的OBJ
unit Obj;
interface
uses
RTTI;
{$RTTI INHERIT}
type TmyObj = class(TObject)
Name:String;
Address:String;
City:String;
procedure SetPropertyValue(sPropName, sPropValue:String);
end;
procedure SetObjProperty(AObject : TObject; propName, propValue:String);
implementation
procedure SetObjProperty(AObject : TObject; propName, propValue:String);
var
context:TRttiContext;
rt: TRttiType;
prop: TRttiProperty;
begin
if not Assigned(AObject) then
exit;
context:=RTTIContext.Create;
rt:=Context.GetType(AObject.ClassType);
for prop in rt.GetProperties do
begin
//do some stuff
end;
Context.Free;
end;
{ TmyObj }
procedure TmyObj.SetPropertyValue(sPropName, sPropValue: String);
begin
SetObjProperty(self, sPropName, sPropValue);
end;
end.
主要
unit Main;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm1 = class(TForm)
edtPropName: TEdit;
Label1: TLabel;
edtPropValue: TEdit;
btnGo: TButton;
procedure btnGoClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
uses
Obj;
{$R *.dfm}
procedure TForm1.btnGoClick(Sender: TObject);
var
myObj:TMyObj;
begin
myObj:=TMyObj.Create;
myObj.SetPropertyValue(edtPropName.Text, edtPropValue.Text);
end;
end.
而不是更改obj.SetPropertyValue
(因为我必须在代码中反复更改它),我只是引用了新程序。
不幸的是,无论我如何尝试在Obj.SetPropertyValyue
中引用该对象,SetObjectProperty
中的对象始终为空 - 因此rt
始终为空且循环不执行任何操作。
我知道在传递一个对象时,我们只是传递一个指针,所以即使我将参数类型更改为CONST
,当我进入新程序时,仍然会得到相同的空/零值。
对我的错误有什么想法吗?我甚至尝试在单位之外引用SetObjProperty
,所以:
thisObj:=TMyObj.Create;
SetObjProperty(thisObj,sThisName, sThisValue);
但我仍然在我的新方法中使用相同的nil
obj。
任何和所有帮助将不胜感激!
答案 0 :(得分:4)
对我的错误有什么看法?
您正在使用RTTI循环浏览属性,但您的TMyObj
没有声明properties。
以下是一个小例子:
program Project62;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
RTTI;
{$RTTI INHERIT}
type
TmyObj = class(TObject)
private
FName:String;
FAddress:String;
FCity:String;
public
property Name: String read FName write FName;
property Address: String read FAddress write FAddress;
procedure SetPropertyValue(sPropName, sPropValue:String);
end;
procedure SetObjProperty(AObject : TObject; propName, propValue:String);
var
context:TRttiContext;
rt: TRttiType;
prop: TRttiProperty;
begin
if not Assigned(AObject) then begin
WriteLn('Not assigned');
exit;
end;
rt:= Context.GetType(AObject.ClassType);
for prop in rt.GetProperties do
begin
if (propName = 'Name') then
prop.SetValue(AObject,propValue)
else if (propName = 'Address') then
prop.SetValue(AObject,propValue);
end;
end;
procedure TmyObj.SetPropertyValue(sPropName, sPropValue: String);
begin
SetObjProperty(self, sPropName, sPropValue);
end;
var
myObj:TMyObj;
begin
myObj:= TMyObj.Create;
myObj.SetPropertyValue('Name', '1');
WriteLn(myObj.Name);
ReadLn;
end.