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

Является ли Delphi "с" ключевым словом плохая практика?

Я читал плохие вещи о ключе с в 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;

Мне кажется, что читать легче, используя ключевое слово с.

Не следует ли использовать ключевое слово с?

4b9b3361

Ответ 1

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

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

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

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

Ответ 2

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

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).

Ответ 3

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

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

with TForm.Create(nil) do
try
  ShowModal;
finally
  Free;
end

Ответ 4

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

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

TAction(Sender).Enabled := Something;

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

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

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

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

Ответ 5

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

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

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

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

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

Ответ 6

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

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

Ответ 7

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

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

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

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;

Ответ 8

Основная проблема с "с" заключается в том, что вы не знаете, где заканчивается его область действия, и вы можете иметь несколько совпадающих с операторами.

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

Одно из предложений сделать его более читаемым (и менее запутанным в более длинном коде) было, если codegear добавила опцию , чтобы разрешить псевдонимы внутри, и, возможно, разрешить несколько сеансов в одном:

procedure TMyForm.AddButtonClick(Sender: TObject);
begin  
  with LongNameDataModule as dm, dm.LongNameTable1 as t1, dm.LongNameTable2 as t2 do
  begin
    t1.Insert;
    t1.FieldByName('Field1').AsString := 'some value';
    t1.FieldByName('Field2').AsString := t2.FieldByName('Field2').AsString;
    t1.Post;
    dm.Connection.Commit;
  end
end;

Ответ 9

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

Реальное зло - это когда у вас сразу несколько открытий.

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

Ответ 10

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

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

Ответ 11

Ваш вопрос - отличный пример того, что "молот - это не всегда решение".

В этом случае "с" не является вашим решением: вы должны перенести эту бизнес-логику из своей формы в свой datamodule. Не делает этого, нарушает Закон Деметры, как mghie (Michael Hieke) уже прокомментировал.

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

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;

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

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

Ответ 12

Здесь есть много превосходных ответов о том, почему утверждение with плохо, поэтому я постараюсь не повторять их. Я много лет использую эту инструкцию, и я очень сильно уклоняюсь от нее. Это частично из-за того, что может быть сложно разобраться в объеме, но в последнее время я начинаю заниматься рефакторингом, и ни один из автоматизированных рефакторингов не работает с выражением - и автоматическое рефакторинг является удивительным.

Также некоторое время назад я сделал видеоролик о том, почему утверждение with is bad, это не одна из моих лучших работ, но Здесь это

Ответ 13

Используйте with только временно (так же, как вы закомментировать временно).

Это помогает вам писать эскизы кода, чтобы получить что-то скомпилированное и быстро выполняемое. Если вы консолидируете решение, очистите его! Удалить with, как вы переместите код в нужное место.

Ответ 14

Текущая инструкция With "опасна", но ее можно существенно улучшить:

  With TForm1.Create (Nil) Do  // New TForm1 instance
    Try
      LogForm (");  // That same instance as parameter to an outer method
      "ShowModal;  // Instance.ShowModal
    Finally
      "Free;  // Instance.Free
    End;

Мое предложение:

  • Не более одного объекта/записи в заголовке.
  • Вложенные не разрешены.
  • Использование "для указания объекта/записи (двойные кавычки аналогичны  к знаку ditto: http://en.wikipedia.org/wiki/Ditto_mark).