对象参数为nil,无法确定原因

时间:2016-03-18 16:19:59

标签: delphi object parameters delphi-10-seattle

我认为这应该是非常直接的,但我不知道为什么这不起作用。

我已经接管了遗留代码,并且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。

任何和所有帮助将不胜感激!

1 个答案:

答案 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.