Является ли Delphi ключевым словом "with" плохая практика? - PullRequest
33 голосов
/ 05 февраля 2009

Я читал плохие вещи о с ключевым словом в delphi, но, на мой взгляд, если вы не используете его слишком часто Это может сделать ваш код простым.

Я часто помещаю все свои TClientDataSets и TFields в TDataModules. Так что в моих формах у меня был такой код

procedure TMyForm.AddButtonClick(Sender: TObject);
begin  
  with LongNameDataModule do
  begin
     LongNameTable1.Insert;
     LongNameTable1_Field1.Value := "some value";
     LongNameTable1_Field2.Value := LongNameTable2_LongNameField1.Value;
     LongNameTable1_Field3.Value := LongNameTable3_LongNameField1.Value;
     LongNameTable1_Field4.Value := LongNameTable4_LongNameField1.Value;
     LongNameTable1.Post;
  end
end;

без с ключевым словом Я должен написать код, подобный этому

    procedure TMyForm.AddButtonClick(Sender: TObject);
    begin            
      LongNameDataModule.LongNameTable1.Insert;
      LongNameDataModule.LongNameTable1_LongNameField1.Value := "some value";

      LongNameDataModule.LongNameTable1_LongNameField2.Value :=
               LongNameDataModule.LongNameTable2_LongNameField1.Value;

      LongNameDataModule.LongNameTable1_LongNameField3.Value :=
               LongNameDataModule.LongNameTable3_LongNameField1.Value;

      LongNameDataModule.LongNameTable1_LongNameField4.Value :=
               LongNameDataModule.LongNameTable4_LongNameField1.Value;

      LongNameDataModule.LongNameTable1.Post;
    end;

Я думаю, что легче читать, используя с ключевым словом .

Следует ли мне избегать использования с ключевым словом ?

Ответы [ 14 ]

58 голосов
/ 05 февраля 2009

Самая большая опасность того, что, помимо патологических состояний, таких как «с A, B, C, D», заключается в том, что ваш код может молча менять значение, не обращая на вас внимания. Рассмотрим этот пример:

with TFoo.Create
try
  Bar := Baz;
  DoSomething();
finally
  Free;
end;

Вы пишете этот код, зная, что Bar является свойством TFoo, а Baz является свойством типа, содержащего метод с этим кодом.

Теперь, спустя два года, какой-то благонамеренный разработчик добавляет свойство Baz в TFoo. Ваш код молча изменил смысл. Компилятор не будет жаловаться, но код теперь не работает.

31 голосов
/ 05 февраля 2009

Ключевое слово с - это хорошая возможность сделать ваш код более читабельным, но есть некоторые подводные камни.

Debugging:

При использовании такого кода:

with TMyClass.Create do
try
  Add('foo');
finally
  Free;
end;

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

Интерфейсы:

При создании интерфейса в с предложением он действует до конца вашего метода:

procedure MemoryHog;
begin
  with GetInterfaceThatTakes50MBOfMemory do
    Whatever;
  ShowMessage('I''m still using 50MB of memory!');
end;

Ясность

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

with TMyForm.Create do
  Width := Width + 2; //which width in this with is width?

Конечно, при наличии повторяющихся имен вы используете свойства и методы класса, объявленного в вашем операторе with (TMyForm).

22 голосов
/ 05 февраля 2009

Оператор with имеет свое место, но я должен согласиться, что чрезмерное использование может привести к неоднозначному коду. Хорошее практическое правило - убедиться, что код стал «более» читаемым и поддерживаемым после добавления оператора with. Если вы чувствуете, что вам нужно добавить комментарии для объяснения кода после добавления оператора, то это, вероятно, плохая идея. Если код более читабелен, как в вашем примере, используйте его.

Кстати: это всегда был один из моих любимых шаблонов в Delphi для отображения модального окна

with TForm.Create(nil) do
try
  ShowModal;
finally
  Free;
end
15 голосов
/ 05 февраля 2009

Я склонен к тому, чтобы вообще запретить утверждение. Как уже говорилось ранее, это может усложнить ситуацию, и мой опыт таков. Много раз отладчик хотел оценивать значения из-за withs, и все часто я нахожу вложенные with, которые приводят к коду, который трудно читать.

Код Брайана кажется читабельным и приятным, но код будет короче, если вы просто введете отправителя напрямую и удалите все сомнения относительно того компонента, который вы включаете:

TAction(Sender).Enabled := Something;

Если вы беспокоитесь о том, чтобы много печатать, я предпочитаю сделать временную ссылку на объект с длинным именем:

var
  t: TTable;
begin
  t := theLongNamedDataModule.WithItsLongNamedTable;
  t.FieldByName(' ');
end;

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

Обновление: Просто наткнулся на длинную статью с небольшим разделом о операторах with: он с ключевым словом. Самая отвратительная, опасная особенность языка в вашей жизни. : -)

8 голосов
/ 05 февраля 2009

Когда я впервые начал программировать на паскале (с TurboPascal!) И учился на ходу, WITH казался замечательным. Как вы говорите, ответ на нудный набор текста и идеально подходит для тех длинных записей. С тех пор, как появился Delphi, я убираю его и призываю других бросить его - аккуратно подытожено Verity на регистре Помимо снижения читабельности, есть две основные причины, по которым я бы избегал этого:

  1. Если вы используете класс, то он вам все равно не нужен - только записи «кажутся» полезными для него.
  2. Использование отладчика для следования коду для объявления с помощью Ctrl-Enter не работает.

Тем не менее, для удобства чтения я все еще использую синтаксис:

procedure ActionOnUpdate( Sender : TObject )
begin
  With Sender as TAction do
    Enabled := Something
end;

Я не видел лучшей конструкции.

6 голосов
/ 17 января 2012

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

Пока что у меня никогда нет необходимости использовать с . Раньше я был амбивалентен по этому поводу, пока не занялся проектом, в котором часто использовалось умственное изгибание double с . На вопрос, намеревался ли первоначальный разработчик ссылаться на элементы в первом с или во втором, если эта неоднозначная ссылка представляла собой with-slip или неуклюжий код, мучения от попыток отладки и стук в эффектах расширения или изменения классов, использующих эти мерзости, просто не стоит никому времени.

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

procedure TMyForm.AddButtonClick(Sender: TObject);
var
  dm: TLongNameDataModuleType
begin  
  dm:=LongNameDataModule;

  dm.LongNameTable1.Insert;
  dm.LongNameTable1_Field1.Value := "some value";
  dm.LongNameTable1_Field2.Value := LongNameTable2_LongNameField1.Value;
  dm.LongNameTable1_Field3.Value := LongNameTable3_LongNameField1.Value;
  dm.LongNameTable1_Field4.Value := LongNameTable4_LongNameField1.Value;
  dm.LongNameTable1.Post;
end;
6 голосов
/ 05 февраля 2009

Ваш пример доступа к модулю данных при нажатии кнопки, на мой взгляд, является плохо продуманным примером. Вся потребность в WITH исчезнет, ​​если вы переместите этот код в модуль данных, где он должен быть. Затем OnClick просто вызывает LongNameDataModule.InsertStuff, и нет необходимости.

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

5 голосов
/ 09 февраля 2009

Я твердо сторонник удаления поддержки WITH в Delphi. Ваш пример использования модуля данных с именованными полями - это единственный случай, когда я смог увидеть, как он работает. В противном случае лучший аргумент против этого был дан Крейгом Штунцем - за который я проголосовал.

Я просто хотел бы отметить, что со временем вы можете в конечном итоге (должны) удалить все кодирование в событиях OnClick, и ваш код в конечном итоге также будет мигрировать из именованных полей в модулях данных в классы, которые обертывают эти данные, и причина для использования WITH уйду

4 голосов
/ 29 апреля 2009

Ваш вопрос является отличным примером того, что «молоток - это не всегда решение».

В этом случае «с» не является вашим решением: вы должны переместить эту бизнес-логику из вашей формы в ваш модуль данных. Невыполнение этого требования нарушает Закон Деметры , как Мгхе (Майкл Хике), уже прокомментированный.

Возможно, ваш пример был просто иллюстративным, но если вы на самом деле используете подобный код в своих проектах, это то, что вы должны сделать вместо:

procedure TLongNameDataModule.AddToLongNameTable1(const NewField1Value: string);
begin  
  LongNameTable1.Insert;
  LongNameTable1_Field1.Value := NewField1Value;
  LongNameTable1_Field2.Value := LongNameTable2_LongNameField1.Value;
  LongNameTable1_Field3.Value := LongNameTable3_LongNameField1.Value;
  LongNameTable1_Field4.Value := LongNameTable4_LongNameField1.Value;
  LongNameTable1.Post;
end;

А затем назовите это из вашей формы следующим образом:

procedure TMyForm.AddButtonClick(Sender: TObject);
begin  
  LongNameDataModule.AddToLongNameTable1('some value');
end;

Это эффективно избавляет вас от оператора with и в то же время делает ваш код более понятным.

Конечно, окружение строк Delphi одинарными кавычками также поможет компилировать их; -)

3 голосов
/ 05 февраля 2009

Насколько я понимаю, С вполне приемлем в случае, если вы дадите. Это, безусловно, улучшает ясность кода.

Настоящее зло в том случае, если у вас есть несколько открыток одновременно.

Кроме того, я считаю, что то, что вы используете с on, имеет большое значение. Если это действительно другой объект, тогда, вероятно, плохая идея. Однако мне не нравится иметь много переменных на одном уровне, даже когда это имеет смысл - как правило, объекты данных, которые содержат целый очень сложный элемент данных - как правило, всю часть работы, с которой программа предназначена для работы. (Я не думаю, что этот случай произошел бы в приложении, у которого такого элемента не было.) Чтобы сделать мир более ясным, я часто использую записи для группировки связанных элементов. Я обнаружил, что почти все, что я использую, предназначены для доступа к таким подгруппам.

...