Подтвердить что ты не робот

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

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

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

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

  • почему он доступен для записи и не доступен для чтения?
  • в каких ситуациях это может быть полезно?

Edit:

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

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

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

Ответ 3

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

Простой совет: не делайте этого.

Ответ 4

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

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

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

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

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

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;

Ответ 5

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

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

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

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