понедельник, 19 января 2009 г.

Осторожно! Помощники класса!

В продолжение темы помощников классов и записей. Я провел небольшое исследование в результате которого выяснилось несколько неприятных моментов применения хелперов. На первый взгляд все прекрасно! Мы можем взять и дополнить любой класс практически любым функционалом. Но не все так радужно.

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

program Project1;

{$APPTYPE CONSOLE}

uses
SysUtils;

type
TSomeObject = class
function X: integer;
end;

TSomeObjectHelper = class helper for TSomeObject
function y: integer;
end;

TSomeObjectHelper2 = class helper for TSomeObject
function z: integer;
end;

{ TSomeObjectHelper }

function TSomeObjectHelper.y: integer;
begin
result := 1;
end;

{ TSomeObject }

function TSomeObject.X: integer;
begin
result := 0;
end;

{ TSomeObjectHelper2 }

function TSomeObjectHelper2.z: integer;
begin
result := 2;
end;

begin
try
with TSomeObject.Create do
begin
writeln(z);
writeln(y);
end;
readln;
except
on E:Exception do
Writeln(E.Classname, ': ', E.Message);
end;
end.

Мы получим ошибку компиляции. Потому что компилятор, видит только один хелпер - TSomeClassHelper2. Если закомнтировать его описание и реализацию, то компилятор увидит второй хелпер.

К чему это может привести? Это может привести к трудноуловимым ошибкам, особенно в больших проектах, разрабатываемых не одним разработчиком. Или, как вариант, представим такую ситуацию: в какой нибудь библиотеке - например FIBPlus или DevExpress вдруг используют хелперы, вы снова добавили хелпер уже в своем коде. Компилятор увидел ВАШ хелпер, а исконный хелпер разработчиков - нет, и все - проект уже не скомпилируется. Ситуация еще больше усугубится если у библиотеки закрыты исходные коды.

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

8 комментариев:

  1. Ну значит можно вычеркнуть хелперы и фич-листа делфи.

    ОтветитьУдалить
  2. Хелперы все же являются довольно мощным и иногда нужным расширением языка. Только вот пользоваться ими нужно аккуратно, а не всовывать их где надо и где не надо.

    Но тем не менее - использование хелперов гораздо лучше чем ковыряться в исходниках VCL, как не так давно предлагали.

    ОтветитьУдалить
  3. Интересно, чем вызвано ограничение именно на 1 хелпер? Например в C# есть "расширители" классов, что по сути дела то же самое. Так там их можно наклепать сколько душе угодно.

    ОтветитьУдалить
  4. Есть еще одна не совсем понятная особенность: классу sealed (наследование запрещено) можно сделать хелпера. Неясно, это by design или ошибка разработчиков.

    ОтветитьУдалить
  5. А разве хелперы имеют доступ к приватным и защищённым членам класса? Если да, то, имхо, ошибка, если нет, то не вижу проблем.

    ОтветитьУдалить
  6. Возвращаясь к напечатанному(с).
    Хелперы имеют доступ к приватным членам класса.

    вот тут:

    http://www.sql.ru/forum/1240944/primenenie-for-in-dlya-spiska-obektov

    обсуждается, как к одному костылю еще один докрутить

    ОтветитьУдалить
  7. Справку читать не пробовали?

    You can define and associate multiple helpers with a single type. However, only zero or one helper applies in any specific location in source code. The helper defined in the nearest scope will apply.

    ОтветитьУдалить