加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

Delphi:为什么TStringlist不能在程序中分配?

发布时间:2020-12-15 04:21:44 所属栏目:大数据 来源:网络整理
导读:第一个程序: procedure TestOne(List : TStringList);var TempList : TStringList;begin TempList := TStringList.Create; TempList.Add('Test'); List := TempList; TempList.Free;end;procedure TForm1.Button1Click(Sender : TObject);var aList : TStri
第一个程序:
procedure TestOne(List : TStringList);
var
  TempList : TStringList;
begin
  TempList := TStringList.Create;
  TempList.Add('Test');
  List := TempList;
  TempList.Free;
end;

procedure TForm1.Button1Click(Sender : TObject);
var
  aList : TStringList;
begin
  aList := TStringList.Create;
  TestOne(aList);
  Memo1.Lines := aList;
end;

当我单击按钮时,备忘录不显示任何内容,并且断点显示该过程不执行此行:

List := TempList;

我修改了程序:

procedure TestTwo(List : TStringList);
var
  TempList : TStringList;
begin
  TempList := TStringList.Create;
  TempList.Add('Test');
  List.Text := TempList.Text;
  //or
  List.Assign(TempList);
  //List := TempList;
  TempList.Free;
end;

这次它有效.

那么为什么它不能使用List:= TempList; ?

解决方法

当您按值传递变量时,Delphi会在堆栈中复制参数值,并且在该方法内对该参数所做的所有更改都将通过该副本完成.

这是帕斯卡自Turbo Pascal时代开始以来的方式,也许从一开始就是这样.考虑一下:

procedure TestInt(Int: Integer);
begin
  Int := 10;
  Writeln(Int); //writes 10
end;

var
  I: Integer;
begin
  I := 5;
  Wirteln(I); //writes 5
  TestInt(I);
  Writeln(I); //also writes 5
end.

现在,当您将对象作为参数传递时,您必须记住对象变量是对对象的引用(指向对象实际存储在堆中的地址的指针).但是,如果通过引用传递参数,则上述规则仍然适用:引用的副本在堆栈中生成.您在方法/过程中对该引用所做的任何更改都是通过该副本完成的.

行List:= TempList;仅更改引用,使其指向不同内存位置中的不同对象.当过程返回时,该值将丢失,与TestInt过程返回时整数值丢失的方式相同.

从不执行该行的事实是优化器的实际应用.由于从未使用过新值,优化器会从最终的exe中删除赋值,并且该行实际上从未执行过.

您可以更改参数声明以通过引用传递它(var参数),但在处理对象时这不是一个好主意,因为您必须考虑谁负责释放对象的内存以避免内存泄漏.

你没有告诉你要完成什么,但看起来像是分配方式,因为赋值将字符串从一个列表复制到另一个列表.您必须考虑直接在List上工作而不使用TempList,如下所示:

procedure TestOne(List : TStringList);
begin
  List.Clear;
  List.Add('Test');
end;

procedure TForm1.Button1Click(Sender : TObject);
var
  aList : TStringList;
begin
  aList := TStringList.Create;
  TestOne(aList);
  Memo1.Lines := aList;
end;

如您所见,结果是相同的.

编辑

Rob在评论中指出了一些重要内容,因此我将解释为什么Button1Click方法的最后一行有效:Memo1.Lines:= aList;

这看起来像是直接分配,但你必须知道你在处理Delphi property.

A property,like a field,defines an attribute of an object. But while a field is merely a storage location whose contents can be examined and changed,a property associates specific actions with reading or modifying its data. Properties provide control over access to an object’s attributes,and they allow attributes to be computed.

The declaration of a property specifies a name and a type,and includes at least one access specifier.

查看如何声明TCustomMemo的Lines属性:

TCustomMemo = class(TCustomEdit)
  ..
  ..
    property Lines: TStrings read FLines write SetLines;

这意味着,当您为属性赋值时,您实际上正在调用SetLines方法,将Value作为参数传递,如下所示:

Memo1.SetLines(AList);

SetLines实现如下所示:

procedure TCustomMemo.SetLines(Value: TStrings);
begin
  FLines.Assign(Value);
end;

因此,您最终发出了相同的TStrings.Assign调用,它将源列表中的所有字符串复制到目标列表.

这是Delphi处理对象属性并保持对对象的明确所有权的方法.每个组件都创建并拥有它自己的子对象,并创建和拥有对象.

对属性的赋值运算符(:=)是sintactic糖,允许组件编写者在读取或写入值时引入副作用,并允许程序员认为该属性是标准字段并享受舒适那副作用.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读