Object 如果将过程指定给对象属性,它是否可以引用该对象的其他属性?
通过一个简单的示例可以最好地显示,问题是底部的ShowMessage:Object 如果将过程指定给对象属性,它是否可以引用该对象的其他属性?,object,delphi,delphi-10.3-rio,Object,Delphi,Delphi 10.3 Rio,通过一个简单的示例可以最好地显示,问题是底部的ShowMessage: type TFrmSelfRef = class(TForm) BtnTest: TButton; procedure BtnTestClick(Sender: TObject); private public procedure ExternalCaller; end; type TProcType = procedure of Object; type TSomeO
type
TFrmSelfRef = class(TForm)
BtnTest: TButton;
procedure BtnTestClick(Sender: TObject);
private
public
procedure ExternalCaller;
end;
type
TProcType = procedure of Object;
type
TSomeObj = class
private
FIdentifier: Integer;
FCaller : TProcType;
public
property Caller : TProcType read FCaller write FCaller;
property Identifier : integer read FIdentifier write FIdentifier;
end;
[snip]
procedure TFrmSelfRef.BtnTestClick(Sender: TObject);
var
lSomeObj: TSomeObj;
begin
lSomeObj := TSomeObj.Create;
lSomeObj.Identifier := 200;
lSomeObj.Caller := ExternalCaller;
lSomeObj.Caller;
lSomeObj.Free;
end;
procedure TFrmSelfRef.ExternalCaller;
begin
ShowMessage('Can I access lSomeObj.Identifier (value:200) here?');
end;
原因:我已经有一个包含调用者需要的所有信息的TSomeObj实例,但是ExternalCaller引用了我不想链接(包含TSomeObj的单元)的其他对象/单元。不,这是不可能的 尽管
ExternalCaller
是一种方法,TProcType
是一种方法类型(“对象”),ExternalCaller()
的隐藏Self
参数是指创建lSomeObj
的TFrmSelfRef
对象;它不是指lSomeObj
另外,你可能已经知道这一点,但从来没有写过 相反,写
lSomeObj := TSomeObj.Create;
try
lSomeObj.Identifier := 200;
lSomeObj.Caller := ExternalCaller;
lSomeObj.Caller;
finally
lSomeObj.Free;
end;
如果出现异常(或者您使用退出
或中断
或继续
)离开)——这在Delphi中很正常——您不能泄漏内存和其他资源!始终使用try..finally
保护资源。显示了一种可能性。它需要一些转发技巧:
type
TSomeObj = class;
TFrmSelfRef = class(TForm)
BtnTest: TButton;
procedure BtnTestClick(Sender: TObject);
private
public
procedure ExternalCaller(ASomeObj: TSomeObj);
end;
TProcType = procedure(Sender: TSomeObj) of Object;
TSomeObj = class
private
FIdentifier: Integer;
FCaller : TProcType;
public
property Caller : TProcType read FCaller write FCaller;
property Identifier : integer read FIdentifier write FIdentifier;
end;
[snip]
procedure TFrmSelfRef.BtnTestClick(Sender: TObject);
var
lSomeObj: TSomeObj;
begin
lSomeObj := TSomeObj.Create;
lSomeObj.Identifier := 200;
lSomeObj.Caller := ExternalCaller;
lSomeObj.Caller(lSomeObj);
end;
procedure TFrmSelfRef.ExternalCaller(ASomeObj: TSomeObj);
begin
ShowMessage('I can access TSomeObj here! Identifier property value: ' + IntToStr(ASomeObj.Identifier));
end;
你所要求的可能是一些丑陋的
t方法
hackery,例如:
类型
TFrmSelfRef=类(TForm)
b测试:t按钮;
程序BtnTestClick(发送方:ToObject);
私有的
公众的
程序外部调用程序;
结束;
类型
TProcType=对象的过程;
类型
TSomeObj=类
私有的
FIdentifier:整数;
FCaller:TProcType;
公众的
属性调用方:TProcType read FCaller write FCaller;
属性标识符:整数读取标识符写入标识符;
结束;
...
程序TFrmSelfRef.BtnTestClick(发送方:TObject);
变量
lSomeObj:TSomeObj;
P:TProcType;
开始
lSomeObj:=TSomeObj.Create;
尝试
lSomeObj.标识符:=200;
//lSomeObj.Caller:=ExternalCaller;
P:=外部调用方;
t方法(P).数据:=lSomeObj;
lSomeObj.Caller:=P;
lSomeObj.呼叫者;
最后
lSomeObj.Free;
结束;
结束;
过程TFrmSelfRef.ExternalCaller;
开始
ShowMessage('标识符为'+IntToStr(TSomeObj(Self.Identifier));
结束;
但如果使用不当,这是非常危险的。我不推荐这种方法!我只是为了完整起见才介绍它
用彼得的解决方案代替
另一种解决方案是将ExternalCaller()
移动到TSomeObj
,例如:
类型
TFrmSelfRef=类(TForm)
b测试:t按钮;
程序BtnTestClick(发送方:ToObject);
私有的
公众的
结束;
类型
TProcType=对象的过程;
类型
TSomeObj=类
私有的
FIdentifier:整数;
FCaller:TProcType;
公众的
程序外部调用程序;
属性调用方:TProcType read FCaller write FCaller;
属性标识符:整数读取标识符写入标识符;
结束;
...
程序TFrmSelfRef.BtnTestClick(发送方:TObject);
变量
lSomeObj:TSomeObj;
P:TProcType;
开始
lSomeObj:=TSomeObj.Create;
尝试
lSomeObj.标识符:=200;
lSomeObj.Caller:=lSomeObj.ExternalCaller;
lSomeObj.呼叫者;
最后
lSomeObj.Free;
结束;
结束;
程序TSomeObj.ExternalCaller;
开始
ShowMessage('标识符为'+IntToStr(标识符));
结束;
@jandogen:当然,你可以使用各种变通方法和黑客。也许其他人能想出一些聪明的办法。(但它值得吗?黑客使代码可读性降低。)Sender
参数是否是一个选项tprotype=对象的过程(发送方:TSomeObj)
。是的,这是最自然的解决方案。(我在最初的评论中提出了这个建议,但我认为您反对对象之间的这种显式连接。)请注意,这基本上是一个类型化的TNotifyEvent。正如Andreas所提到的,这是一种非常惯用的方法。这个答案使问题看起来像是询问是否可以将参数传递给过程。。。。安德烈亚斯删除的答案是正确的,我同意…@Sertac。我真的不明白这是怎么回答这个问题的。是的,我同意这个诡计——我不会那么做。但将ExternalCaller()移动到TSomeObj是我试图阻止的……事实上,这也是我想到的第一个黑客。在某些情况下,它实际上可能是一个好的解决方案(我在自己的代码中使用过一次),但大多数情况下,它可能不是。
type
TSomeObj = class;
TFrmSelfRef = class(TForm)
BtnTest: TButton;
procedure BtnTestClick(Sender: TObject);
private
public
procedure ExternalCaller(ASomeObj: TSomeObj);
end;
TProcType = procedure(Sender: TSomeObj) of Object;
TSomeObj = class
private
FIdentifier: Integer;
FCaller : TProcType;
public
property Caller : TProcType read FCaller write FCaller;
property Identifier : integer read FIdentifier write FIdentifier;
end;
[snip]
procedure TFrmSelfRef.BtnTestClick(Sender: TObject);
var
lSomeObj: TSomeObj;
begin
lSomeObj := TSomeObj.Create;
lSomeObj.Identifier := 200;
lSomeObj.Caller := ExternalCaller;
lSomeObj.Caller(lSomeObj);
end;
procedure TFrmSelfRef.ExternalCaller(ASomeObj: TSomeObj);
begin
ShowMessage('I can access TSomeObj here! Identifier property value: ' + IntToStr(ASomeObj.Identifier));
end;