Delphi2010:混淆泛型类型TList场景?传递值还是引用? 几天前我在一个项目中使用泛型TLIST时遇到了一个问题。我在一个简单的测试项目中测试了它,得到了同样的问题。以下是确切的代码: type TMyPoint = record x: Integer; y: Integer; end; TShape = record Corners: TList<TMyPoint>; end; TForm1 = class(TForm) Button1: TButton; Label1: TLabel; procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); private Shape_List: TList<TShape>; public end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); var Shape: TShape; FirstPoint: TMyPoint; SecondPoint: TMyPoint; Temp: TMyPoint; begin // Create the corners list Shape.Corners := TList<TMyPoint>.Create; // Add the first point to corners FirstPoint.x := 10; FirstPoint.y := 20; Shape.Corners.Add(FirstPoint); // Add the shape to the Shape_List Shape_List.Add(Shape); // Clear the shape corners Shape.Corners.Clear; // Add another point to corners SecondPoint.x := 100; SecondPoint.y := 200; Shape.Corners.Add(SecondPoint); // Show the x of the first point of the first shape Label1.Caption := IntToStr(Shape_List[0].Corners[0].x); end; procedure TForm1.FormCreate(Sender: TObject); begin Shape_List := TList<TShape>.Create; end; 类型 TMyPoint=记录 x:整数; y:整数; 结束; t形状=记录 角落:TList; 结束; TForm1=类(TForm) 按钮1:t按钮; 标签1:TLabel; 过程表单创建(发送方:ToObject); 程序按钮1点击(发送方:ToObject); 私有的 形状列表:TList; 公众的 结束; 变量 表1:TForm1; 实施 {$R*.dfm} 程序TForm1.按钮1单击(发送方:TObject); 变量 形状:t形; 第一点:TMyPoint; 第二点:TMyPoint; 温度:TMyPoint; 开始 //创建角点列表 Shape.Corners:=TList.Create; //将第一个点添加到角点 第一点x:=10; 第一点y:=20; 形状。角点。添加(第一点); //将形状添加到“形状”列表中 形状列表。添加(形状); //清除形状角 形状、棱角、清晰; //将另一个点添加到角点 第二点x:=100; 第二点y=200; 形状。角点。添加(第二点); //显示第一个形状的第一个点的x Label1.Caption:=IntToStr(形状列表[0]。角点[0].x); 结束; 过程TForm1.FormCreate(发送方:TObject); 开始 形状列表:=TList.Create; 结束;

Delphi2010:混淆泛型类型TList场景?传递值还是引用? 几天前我在一个项目中使用泛型TLIST时遇到了一个问题。我在一个简单的测试项目中测试了它,得到了同样的问题。以下是确切的代码: type TMyPoint = record x: Integer; y: Integer; end; TShape = record Corners: TList<TMyPoint>; end; TForm1 = class(TForm) Button1: TButton; Label1: TLabel; procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); private Shape_List: TList<TShape>; public end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); var Shape: TShape; FirstPoint: TMyPoint; SecondPoint: TMyPoint; Temp: TMyPoint; begin // Create the corners list Shape.Corners := TList<TMyPoint>.Create; // Add the first point to corners FirstPoint.x := 10; FirstPoint.y := 20; Shape.Corners.Add(FirstPoint); // Add the shape to the Shape_List Shape_List.Add(Shape); // Clear the shape corners Shape.Corners.Clear; // Add another point to corners SecondPoint.x := 100; SecondPoint.y := 200; Shape.Corners.Add(SecondPoint); // Show the x of the first point of the first shape Label1.Caption := IntToStr(Shape_List[0].Corners[0].x); end; procedure TForm1.FormCreate(Sender: TObject); begin Shape_List := TList<TShape>.Create; end; 类型 TMyPoint=记录 x:整数; y:整数; 结束; t形状=记录 角落:TList; 结束; TForm1=类(TForm) 按钮1:t按钮; 标签1:TLabel; 过程表单创建(发送方:ToObject); 程序按钮1点击(发送方:ToObject); 私有的 形状列表:TList; 公众的 结束; 变量 表1:TForm1; 实施 {$R*.dfm} 程序TForm1.按钮1单击(发送方:TObject); 变量 形状:t形; 第一点:TMyPoint; 第二点:TMyPoint; 温度:TMyPoint; 开始 //创建角点列表 Shape.Corners:=TList.Create; //将第一个点添加到角点 第一点x:=10; 第一点y:=20; 形状。角点。添加(第一点); //将形状添加到“形状”列表中 形状列表。添加(形状); //清除形状角 形状、棱角、清晰; //将另一个点添加到角点 第二点x:=100; 第二点y=200; 形状。角点。添加(第二点); //显示第一个形状的第一个点的x Label1.Caption:=IntToStr(形状列表[0]。角点[0].x); 结束; 过程TForm1.FormCreate(发送方:TObject); 开始 形状列表:=TList.Create; 结束;,delphi,generics,record,tlist,Delphi,Generics,Record,Tlist,标签1.标题将是100而不是10!为什么是这样?我认为TList.Add(const value)是按值传递而不是按引用传递 添加FirstPoint后,您可以清除角点(之后,列表为空)。然后添加成为第一个元素(索引0)的SecondPoint 编辑:举例说明: var Shape1, Shape2: TShape; begin Shape1.Corners := TList<TMyPoint>.Create; Shape2 := Shape1; OutputDebu

标签1.标题将是100而不是10!为什么是这样?我认为
TList.Add(const value)
是按值传递而不是按引用传递

添加
FirstPoint
后,您可以
清除
角点
(之后,列表为空)。然后添加成为第一个元素(索引0)的
SecondPoint

编辑:举例说明:

var
  Shape1, Shape2: TShape;
begin
  Shape1.Corners := TList<TMyPoint>.Create;
  Shape2 := Shape1;
  OutputDebugString(PChar(Format('Shape1.Corners: $%.8x', [Integer(Shape1.Corners)])));
  OutputDebugString(PChar(Format('Shape2.Corners: $%.8x', [Integer(Shape2.Corners)])));
end;
var
形状1,形状2:t形状;
开始
Shape1.Corners:=TList.Create;
Shape2:=Shape1;
OutputDebugString(PChar格式('Shape1.Corners:$%.8x',[Integer(Shape1.Corners)]);
OutputDebugString(PChar(格式('Shape2.Corners:$%.8x',[Integer(Shape2.Corners)]));
结束;

Shape1.Corners
Shape2.Corners
指向同一列表。

否,它是通过引用传递的,因为它是作为常量参数传递的(请参见:)

在您的过程中添加了一些注释,以指出“bug”的确切位置

procedure TForm1.按钮1点击(发送方:TObject);
变量
形状:t形;
第一点:TMyPoint;
第二点:TMyPoint;
温度:TMyPoint;
开始
//创建角点列表
Shape.Corners:=TList.Create;//我们创建一个新的TList对象。形状。角是一个参考
//将第一个点添加到角点
第一点x:=10;
第一点y:=20;
形状。角点。添加(第一点);//将FirstPoint添加到我们在步骤1中创建的列表中。
//将形状添加到“形状”列表中
形状列表。添加(形状);//将形状记录的副本添加到形状列表中
//清除形状角
Shape.Corners.Clear;//清除形状。角参照。这将有效地清除角点列表
//在刚才添加到Shape_列表的形状中,因为它包含相同的
//参考资料。
//将另一个点添加到角点
第二点x:=100;
第二点y=200;
形状。角点。添加(第二点);//将新点添加到“角点”列表中。记住,角落实际上是
//推荐人。添加到形状列表的第一个形状包含一个副本
//完全相同的引用,所以实际上添加了第一点
//到Shape.Corners和Shape_列表[0]。Corners。
//显示第一个形状的第一个点的x
标签1.标题:=IntToStr(形状列表[0]。角点[0].x);//是的,你刚刚加了那一点,所以你得到100分
结束;

由于列表项是记录,列表仍将包含添加项的副本。那么“常量值”和“var值”之间的区别是什么?他们两个都是通过引用传递的吗@弗洛姆烯醇-完全正确。不同之处在于,
var value
允许修改传递给它的函数/过程中的参数,而
const value
则不允许修改。@Flom Enol-查看此处以获得更多解释()我不知道。谢谢你的回答。我来看看这篇文章。你没有仔细阅读代码。我在“shape_列表”中显示了第一个形状的第一个角,而不是局部变量。将形状添加到“形状”列表后进行更改。我清除了局部变量(Shape)的角点,而不是列表中的角点(应该是Shape的副本)。更正:局部变量Shape可能是副本(因为它是记录),但角点字段是引用。因此,Shape可能是Shape_列表[0]的副本,但Shape.Corners指向与Shape_列表[0]相同的列表。Corners.+1,发生这种情况是因为Shape.Corners是一个引用。在原始代码中添加了一个带有注释的答案,使其更加明显。感谢您让我明白。我想的是,当制作记录的副本时,其中的TList也会被复制,这是一个错误的假设。你确定“TMyPoint数组”吗?AFAIK动态数组不像字符串那样是“写时复制”。就连帮助也提到了这一点。像Uwe一样,我也在想动态数组能解决这个问题吗?它真的像字符串吗?@Uwe Raabe,@Flom:搞错了,动态数组不是写时复制的。删除该评论,以确保没有人将其视为“真实”。
procedure TForm1.Button1Click(Sender: TObject);
var
  Shape: TShape;
  FirstPoint: TMyPoint;
  SecondPoint: TMyPoint;
  Temp: TMyPoint;
begin
  // Create the corners list
  Shape.Corners := TList<TMyPoint>.Create; // We create a new TList<TMyPOint> OBJECT. Shape.Corners is a reference
  // Add the first point to corners
  FirstPoint.x := 10;
  FirstPoint.y := 20;
  Shape.Corners.Add(FirstPoint); // Add FirstPoint to the list we created at step 1.
  // Add the shape to the Shape_List
  Shape_List.Add(Shape); // Add a copy of the Shape record to the Shape_List

  // Clear the shape corners
  Shape.Corners.Clear; // Clear the Shape.Corners reference. This effectively clears the list of corners
                       // in the Shape you just added to Shape_List because it contains the same
                       // reference.

  // Add another point to corners
  SecondPoint.x := 100;
  SecondPoint.y := 200;
  Shape.Corners.Add(SecondPoint); // Add a new point to the Corners list. Remamber, Corners is actually
                                  // a reference. The first Shape you added to Shape_List contains a copy
                                  // of this exact same reference, so you're effectively adding a first point
                                  // to both Shape.Corners and Shape_List[0].Corners.

  // Show the x of the first point of the first shape
  Label1.Caption := IntToStr(Shape_List[0].Corners[0].x); // Yup, you just added that point, so you get 100
end;