德尔福2010:令人困惑的泛型类型 TList 场景?按值传递还是按引用传递?

StackOverflow https://stackoverflow.com/questions/6057298

  •  15-11-2019
  •  | 
  •  

几天前,我在项目中使用 Generic 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;

Label1.Caption 将是 100 不是 10 !为什么会这样呢?我想 TList.Add(const value) 是按值传递而不是按引用传递!

有帮助吗?

解决方案

在您的程序中添加了一些注释,以准确指出“错误”的位置。

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;

其他提示

添加后 FirstPoint, , 你 ClearCorners (之后,列表为空)。然后你添加 SecondPoint 它成为第一个元素(索引 0)。

编辑:为了显示:

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;

Shape1.CornersShape2.Corners 指向同一个列表。

不,它是通过引用传递的,因为它是作为常量参数传递的(请参阅: http://docwiki.embarcadero.com/VCL/en/Generics.Collections.TList.Add).

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top