Какие-нибудь ресурсы / учебные пособия по использованию вложенных операторов «С» в Delphi? - PullRequest
6 голосов
/ 17 января 2012

Я пытаюсь понять, как правильно использовать операторы в delphi.

В целом, кажется, довольно просто делать простые вещи, но мне интересно найти несколько хороших примеров кода и / или учебных пособий по использованию вложенных операторов. Е.Г.

with object1, object2, etc... do 
  begin
  statements
  end;

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

Любой совет приветствуется.

Ответы [ 5 ]

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

Лучший совет, который я могу вам дать:

Не использовать никогда.

Если вам хочется использовать «с», иди и ляг, пока чувство не пройдет.

Если вам захочется использовать гнездо с помощью, ударьте молотком по руке, пока желание не исчезнет.

'with' - это просто ошибка, ожидающая своего появления. Изменение классов, используемых с ним, может изменить смысл вашего кода. Это создает неточную семантику, а это всегда плохо.

Сохранение нажатий клавиш никогда не является хорошей причиной для использования «с». Еще несколько нажатий клавиш теперь избавят вас от боли.

«С» следует избегать.

7 голосов
/ 22 января 2012

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

Как вы, возможно, уже поняли, проблема only с (неопубликованным) with состоит в том, что вместо обращения к конкретному члену экземпляра вы можетеобращаясь к члену Self (или экземпляру с одного вложенного уровня вверх) с тем же именем, которое вы явно не намеревались:

procedure TForm1.SomeRoutine;
var
  Button: TControl;
begin
  Button := Button1;
  with Button do
    Caption := 'Press here';
end;

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

procedure TForm1.SomeRoutine;
begin
  with Button1 do
    Caption := 'Press here';
end;

... потому что, возможно, Button1 объявлен как некоторый экзотический тип кнопки, у которого имеет заголовок,но имя свойства может быть Title, Beschriftung или Legende.

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

procedure TForm1.SomeRoutine;
begin
  with Button1 do
    Cpation := 'Press here';
end;

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

Такого рода ошибки совершаются очень легко.Я, вами и любым другим (опытным) разработчиком.Особенно, когда вы работаете или работаете с кодом, который находится в стадии разработки или подвергается рефакторингу.И очевидно, что при вложенных with s проблемы отладки из-за этих ошибок накапливаются до экспоненциальных пропорций.

Теперь, в отличие от всех остальных здесь, я использую with довольно часто, но только на фиксированныхтипы библиотек, членами которых являются , никогда , чтобы стать переименованными.Например: TRect, TPoint, TMessage, TGridRect, TControl, TCanvas, и т.д.Если вы действительно хотите использовать with, я предлагаю следующее:

  • Безопасный пример:

    with ARect do
      ExcludeClipRect(DC, Left, Top, Right, Bottom);  //TRect will always have these
    
  • Хитрый пример:

    with Query, Parameters do
    begin
      Connection := AConnection;
      ParamValues['ID'] := ID; //TParameters has a few same named members as dataset
      Open;
    end;
    
  • Плохой пример:

    with TMyLabel do
      Color := clYellow; //My label may become transparent in future
    

Редактировать:

Я стал участником-with-camp.

Мои примеры выше предполагают опасность с with только в направлении вверх, например, смешивая Child.Caption с Self.Caption.Но недавно, когда я переносил некоторый код из D7 в XE2, у меня возникли проблемы в нисходящем направлении.На самом деле, используя «безопасный пример» из вышеприведенного, достаточно точно:

  with GripRect[I] do
  begin
    ...
    Left := Width - W[I];

Намерение Width будет таким же, как у Self, но так как TRect в XE2 также имеет член Width, япришлось переписать код так:

    Left := Self.Width - W[I];

Вывод: действительно безопасного использования with.

не существует
7 голосов
/ 17 января 2012

Выдержка из онлайн-справки гласит:

Когда после с появлением нескольких объектов или записей, весь оператор обрабатывается как серия вложенных операторов,Таким образом:

with obj1, obj2, ..., objn do statement

эквивалентно:

 with obj1 do
  with obj2 do
    ...
    with objn do
      // statement

В этом случае каждая ссылка на переменную или имя метода в выражении интерпретируется, если возможно, как член objn;в противном случае он интерпретируется, если возможно, как член objn1;и так далее.То же правило применяется к интерпретации самих объектов, так что, например, если objn является членом обоих obj1 и obj2, оно интерпретируется как obj2.objn.

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

Delphi's with проблематичен - его «неточная семантика» действительно может укусить вас сзади.Вложенный with ... OMG ... Это катастрофа, ожидающая случиться.Никогда не нуждался во вложенной версии на 13 лет Delphi.И я буду избегать в течение следующих лет.

РЕДАКТИРОВАТЬ: В других обсуждениях о with некоторые указали, что новый синтаксис был бы хорош.Отправной точкой является Vb.Net with:

With Something.Somewhere
  .over.the.rainbow = True
End With

Я немного не люблю (по вкусу), но это намного лучше, чем Delphi.Предложение альтернативного синтаксиса, которое я видел в этих обсуждениях:

With SS:Something.Somewhere.over do
  SS.the.rainbow = true;
  SS.the.Storm = false;
end;
2 голосов
/ 18 января 2012

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

Но у людей есть эта проблема, которая в психологии называется теорией куска. Когда вам предоставляют семь вещей, которые вы можете отслеживать в своем уме, один выпадает, потому что ваш мозг имеет около 6 локальных регистров для хранения вещей. Представьте, что здесь появляется простой идентификатор Foo:

   with EXPRESSION1 do begin
     with EXPRESSION2 do begin
               Foo;
     end;
   end;

Вышеуказанное для всех намерений идентично with EXPRESSION1, EXPRESSION2 do begin....

Итак, давайте посмотрим, как простые правила, такие как область действия, становятся слишком сложными, чтобы им следовать через некоторое время. Давайте представим, что у нас есть следующие уровни области видимости в некотором приложении delphi, в котором мы работаем:

  • Область действия каждой единицы, указанной в ваших предложениях use.
  • Область действия раздела реализации вашего подразделения (Внутренние устройства)
  • Область действия класса (идентификаторы внутри вашего текущего класса, если вы пишете метод)
  • Локальная область действия процедуры или метода (раздел var в процедуре или функции).
  • Первый с утверждением в примере выше.
  • Второй с утверждением в примере выше.

Обновление Дэвид указал мне, что я должен упомянуть, что вместо 6 "областей" выше, у нас действительно есть 5 + x областей, где x - длина обоих ваших предложений uses.

Теперь проблема не в том, что утверждение WITH неясно, а в том, что люди могут легко потеряться, если у вас есть 6 слоев лексической области видимости, как указано выше, и требуют, чтобы вы не только знали обо всех местах, где Foo определено, потому что если вы думали, что в самом внутреннем операторе With определено что-то с именем Foo, то это не слишком неприятная и трудная для поиска ошибка в вашем коде. Итак, у нас есть очень умные, очень способные люди, такие как Ник, которые говорят очень разумные вещи, такие как «никогда не используйте с». И я согласен на 99% с Ником.

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

WITH не вся проблема в плохом коде, это просто самая распространенная пчела в капоте разработчика Delphi. Может быть, это привлекает больше внимания, чем чрезмерно большие предложения использования, но за всю мою карьеру предложения зависимости и адского огромного использования сделали в 100 раз больше, чтобы усложнить жизнь, чем WITH. Поэтому я думаю, что WITH considered harmful перевыполнено, а другие вещи, которые следует учитывать больше, рассматриваются.

Разумной альтернативой использованию с является использование однобуквенного имени переменной (я знаю, согласен и не согласен), и избегайте всей двусмысленности:

procedure NoWithPlease;
var
   a:TSomething;
begin
   a :=  Some.Long.Expression[x].That.You.Dont.Want.To.Repeat.Six.Times;
   a.Foo := 'test';
   a.Bar := 'test2'
end;

Это лучше, многие скажут, чем это:

procedure WithPleasure;
begin
   with Some.Long.Expression[x].That.You.Dont.Want.To.Repeat.Six.Times do begin
     Foo := 'test';
     Bar := 'test2'
   end;
end;

Теперь я слишком много укушен WITH, чтобы отстаивать его неограниченное использование. Но я также думаю, что бывают ситуации, когда это лучше, чем делать локальные переменные. Для этого не требуется объявлять локальную переменную или определять тип выражения. Если бы у delphi было type inference (ключевое слово auto в C ++), то я бы сказал, что мы могли бы легко обойтись без WITH полностью, но на самом деле это своего рода способ избежать статического создания зависимости от реализации. типов, а также возможность создавать читаемые подобласти, это может иногда облегчать чтение вашего кода, а иногда и ухудшать его, особенно когда существует более одного уровня операторов WITH.

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

Мои предложенные правила:

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

  2. Всегда избегайте многоуровневых WITH операторов.

...