Delphi 对象参数为nil,can';我无法确定原因

Delphi 对象参数为nil,can';我无法确定原因,delphi,object,parameters,delphi-10-seattle,Delphi,Object,Parameters,Delphi 10 Seattle,我认为这应该是非常直接的,但我不知道为什么这不起作用 我已经接管了遗留代码,dll中使用的一些对象变得不可管理。几个对象具有相同的过程 SetPropertyValue(propName,propValue:string); 现在,这些方法基本上都是巨型的if..else语句,用于检查propName并指定propValue是否与objects属性匹配: if propName='name' then name:=propValue else if propName='address' t

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

我已经接管了遗留代码,dll中使用的一些对象变得不可管理。几个对象具有相同的过程

SetPropertyValue(propName,propValue:string);
现在,这些方法基本上都是巨型的
if..else
语句,用于检查
propName
并指定
propValue
是否与objects属性匹配:

if propName='name' then
  name:=propValue
else if propName='address' then
  address:=propValue
等等

每次对象获得新属性(或属性类型更改,因此传入的值参数需要进行不同的强制转换)时,该方法都需要更新—显然,这是一项不需要更新的琐事

我选择编写一个全局方法来设置一个动态的对象属性,该属性需要最少的维护

下面是我目前正在做的一个简短的例子。有两个单元,Obj和Main-其中Main是一个VCL表单,有两个编辑框和一个按钮,我使用按钮单击触发SetPropertyValue:

Obj

主要

我没有更改
obj.SetPropertyValue
(因为我必须在代码中反复更改它),而是引用了新的过程

不幸的是,无论我如何尝试在
Obj.SetPropertyValyue
中引用对象,它在
SetObjectProperty
中总是空的,因此
rt
总是空的,循环没有任何作用

我知道当传递一个对象时,我们只是传递一个指针,所以即使我将参数类型更改为
CONST
,当我进入新过程时,仍然会得到相同的空/nil值

我有什么想法不对吗?我甚至尝试在装置外部引用
SetObjProperty
,因此:

thisObj:=TMyObj.Create;
SetObjProperty(thisObj,sThisName, sThisValue);
但在我的新方法中,我仍然得到了相同的
nil
obj

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

我有什么想法不对吗

您正在使用循环遍历属性,但您的
TMyObj
没有声明

下面是一个小示例,说明如何操作:

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.

不要
Free
TRttiContext
获取的对象,它们属于内部缓存,将自动释放。您还应该声明一个
TRttiContext
变量,并在函数退出时使其超出范围,以确保缓存在函数运行期间保持有效。调用
TRttiContext.Create
是可选的。谢谢@RemyLebeau-少了一件需要担心的事情!这是一个漫长的星期,所以我会抓起这一个直到累了。你是100%正确的,这些不是属性的事实意味着,除了将它们重新声明为属性外,我还应该使用RTTIFields!!!一旦你指出了这一点,我就发现了我的错误,并立即将其纠正。一个在周五结束的好方法-谢谢你的帮助!
thisObj:=TMyObj.Create;
SetObjProperty(thisObj,sThisName, sThisValue);
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.