Почему Self назначается в Delphi?

этот код в приложении GUI компилируется и запускается:

procedure TForm1.Button1Click(Sender: TObject);
begin
  Self := TForm1.Create(Owner);
end;

(протестировано с Delphi 6 и 2009)

  • почему Self writable и не только для чтения?
  • в каких ситуациях это может пригодиться?

изменить:

  • это также возможно в Delphi Prism? (Я думаю, да, это так, см. здесь)

обновление: Приложения/библиотеки Delphi, которые используют Self задание:

5 ответов


Это не так плохо, как могло быть. Я только что протестировал его в Delphi 2009, и казалось бы, что, хотя параметр Self не использует const семантика, которую вы, похоже, подразумеваете, она должна, она также не использует var семантика, поэтому вы можете изменить все, что хотите в своем методе, не теряя ссылку вызывающего абонента на ваш объект. Это было бы очень плохо.

Что касается причины, почему один из двух ответов. Либо простой недосмотр или то, что предложил Марко: позволить вам передать себя var


может быть, разрешить переход к параметрам const или var?

Это может быть артефакт, так как система не имеет себя нигде слева от: = знака.


назначение себя настолько нелогично и бесполезно, что эта "функция", вероятно, является упущением. И, как и с назначаемыми константами, не всегда легко исправить такие проблемы.

простой совет здесь: не делай этого.


на самом деле" Self " - это просто ссылка на место в стеке, которое хранит адрес, указывающий на объект в куче. Принудительное чтение только для этой переменной возможно, по-видимому, дизайнер решил этого не делать. Я считаю это решение произвольным.

Не вижу ни одного случая, когда это полезно, это просто изменит значение в стеке. Кроме того, изменение этого значения может быть опасным, так как нет гарантии, что поведение кода, являющегося членом экземпляра ссылки, будет согласованность между версиями компилятора.

обновление: в ответ PatrickvL комментарий

"переменная "" я " не находится на стек (насколько мне известно, это никогда не так); Значение не помещается в зарегистрируйтесь (EAX, чтобы быть точным) непосредственно перед вызывается любой метод объекта. –

нет, Self имеет фактический адрес в памяти. Попробуйте этот код, чтобы убедиться сами.

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowMessage(IntToStr(Integer(@Self)));
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  newform: TForm;
  p: ^Integer;
begin
  Self.Caption := 'TheOriginal';
  newform := TForm.Create(nil);
  try
    newform.Caption := 'TheNewOne';
    // The following two lines is, technically, the same as
    //   Self := newform;
    p := Pointer(@Self);
    p^ := Integer(newform);
    ShowMessage(Self.Caption);  // This will show 'TheNewOne' instead of 'TheOriginal'
  finally
    Self.Free; // Relax, this will free TheNewOne rather than TheOriginal
  end;
end;

иногда, когда вы хотите оптимизировать метод, насколько это возможно (без использования сборки), "Self" может использоваться как "свободная" переменная - это может означать разницу между использованием стека и использованием регистров.

конечно, содержимое стека, скорее всего, уже присутствует в кэше CPU, поэтому он должен быть быстрым для доступа, но регистры еще быстрее.

Как sidenote: я все еще пропускаю дни, когда я программировал на у Motorola 68000 Amiga была роскошь 16 данных и 16 адресных регистров.... Я не могу поверить, что мир решил пойти с ограниченными 4 регистрами линейки процессоров 80x86!

и в качестве заключительного замечания я иногда использую Self, поскольку оптимизатор Delphi-это, ну, не оптимизация это хорошо, на самом деле. (По крайней мере, он бледнеет по сравнению с тем, что можно найти в различных оптимизаторах LLVM, например.) ИМХО, и YMMV конечно.