Почему Self назначается в Delphi? - PullRequest
17 голосов
/ 02 мая 2009

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

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

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

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

Edit:

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

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

Ответы [ 5 ]

11 голосов
/ 02 мая 2009

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

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

7 голосов
/ 02 мая 2009

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

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

4 голосов
/ 02 мая 2009

Присвоение Себя настолько нелогично и бесполезно, что эта «особенность», вероятно, является упущением Как и в случае с присваиваемыми константами, такие проблемы не всегда легко исправить.

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

2 голосов
/ 02 мая 2009

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

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

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

«Переменная» «Self» не находится на стек (насколько мне известно, это никогда не бывает); Вместо этого это значение помещается в зарегистрироваться (точнее, 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;
1 голос
/ 30 марта 2010

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

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

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

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

...