Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2006.02.12;
Скачать: CL | DM;

Вниз

Уничтожение компонентов   Найти похожие ветки 

 
z0ne   (2005-08-18 11:57) [0]

1. есть связка компонентов: ТКомпонент1 использует ТКомпонент2
2. ТКомпонент2 могут использовать также и ТКомпонент3 и ТКомпонент4
3. все компоненты невизуальные и набросаны на DataModule
4. + есть возможность создания экземпляров ТКомпонент3 или  ТКомпонент1 в run-time.

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

мне нужно определить порядок уничтожения компонентов, чтобы ТКомпонент2 был уничтожен последним. Иначе при обращении к ТКомпонент2 из, например, ТКомпонент3 получаю Access Violation


 
Джо ©   (2005-08-18 13:05) [1]

Упростим ситуацию для наглядности.

 TInnerControl = class (TControl)
 end;

 TOuterControl = class (TControl)
 private
   FMyControl: TControl;
   procedure SetMyControl(const Value: TControl);
 protected
   procedure Notification(AComponent: TComponent;
     Operation: TOperation); override;
 published
   property MyControl: TControl read FMyControl write SetMyControl;
 end;

implementation

procedure TOuterControl.Notification(AComponent: TComponent;
 Operation: TOperation);
begin
 inherited Notification(AComponent, Operation);
 if Operation = opRemove then
   if AComponent = MyControl then
     MyControl := nil;
end;

procedure TOuterControl.SetMyControl(const Value: TControl);
begin
 FMyControl := Value;
 if FMyControl <> nil then
   FMyControl.FreeNotification(Self);
end;


Перед своим уничтожением, объект класса TInner (неважно, каким образом это произойдет) уведомит об этом TOuter. И он вовремя обнулит свою ссылку на удаляемый объект.


 
Юрий Зотов ©   (2005-08-18 13:12) [2]

> z0ne   (18.08.05 11:57)

> нужно определить порядок уничтожения компонентов

Не нужно определять порядок уничтожения компонентов. Нужно у компонентов, ссылающихся на другие компоненты, перекрыть метод Notification и в нем очищать ссылки. А потенциально опасных местах кода, перед обращением по этим ссылкам проверять их на nil, вот и все.

type
 TComponent2 = class(...)
   ...
 end;

 TComponent1 = class(...)
 private
   FComponent2: TComponent2;
   procedure SetComponent2(const Value: TComponent2);
 protected
   procedure Notification(AComponent: TComponent; Operation: TOperation); override;
   ...
   procedure DoSomethingWithComponent2;
   ...
 published
   ...
   property Component2: TComponent2 read FComponent2 write SetComponent2;
   ...
 end;

procedure TComponent1.Notification(AComponent: TComponent; Operation: TOperation); override;
begin
 inherited;
 if (Operation = opRemove) and (AComponent = FComponent2) then
   FComponent2 := nil
end;

procedure TComponent1.SetComponent2(const Value: TComponent2);
begin
 if FComponent2 <> Value then
 begin
   if FComponent2 <> nil then
     RemoveFreeNotification(FComponent2);
   FComponent2 := Value;
   if FComponent2 <> nil then
     FreeNotification(FComponent2)
 end
end;

procedure TComponent1.DoSomethingWithComponent2;
begin
 if FComponent2 <> nil then
   ...
end;


 
z0ne   (2005-08-18 13:20) [3]

>Перед своим уничтожением, объект класса TInner (неважно, каким >образом это произойдет) уведомит об этом TOuter. И он вовремя >обнулит свою ссылку на удаляемый объект.

проблема как раз в том что ТКомпонент2 ДОЛЖЕН жить пока существуют на него ссылки!!! т.е. не давать себя разрушить.
и как посчитать ссылки ??? делать наследников для ТКомпонент1,3,4???


 
Юрий Зотов ©   (2005-08-18 14:07) [4]

> z0ne   (18.08.05 13:20) [3]

> ТКомпонент2 ДОЛЖЕН жить пока существуют на него ссылки!!!

Не должен. А если без этого что-то не получается - значит, это "что-то" неверно задумано или неверно спроектировано.

Поэтому давайте начнем с начала - в чем, собственно, задумка-то?


 
Reindeer Moss Eater ©   (2005-08-18 14:07) [5]

проблема как раз в том что ТКомпонент2 ДОЛЖЕН жить пока существуют на него ссылки!!!

Надуманная проблема.
Метод Notification как раз предназначен для убийства недействительных ссылок.


 
z0ne   (2005-08-18 15:20) [6]

>Поэтому давайте начнем с начала - в чем, собственно, задумка-то?

всегда все приходят к этому главному вопросу :)
компонент который "должен жить" это прослойка в наследнике от TDataSet которая отвечает за работу с конкретным SQLСервером соответственно черезнего работают все запросы типа StartTransaction, ExecSQL, SELECT ну и прочие.
на него опирается ещё пара-тройка компонент, которые хотят общаться с базой.
т.е. схема такая T_DataSet -> TProv -> IBSQL примерно!!!
и вот убивание этого самого TProv и портит мне жисть.
так что вариант с Notification и обнулением ссылки .... неподходит :(
проект где используются эта "штуковина" не первый ...
может раньше как-то складывалось всё удачно, назнаю!

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


 
Reindeer Moss Eater ©   (2005-08-18 15:57) [7]

и вот убивание этого самого TProv и портит мне жисть.
так что вариант с Notification и обнулением ссылки .... неподходит :(


Бред.
Жизнь будет портиться только если ты не проверяешь свойства - объекты на nil перед тем как их использовать.

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

Ну вот. А говорили нет пророка в своем отечестве. А они тут пачками ходят.
:)))


 
z0ne   (2005-08-18 16:41) [8]

>не проверяешь свойства - объекты на nil перед тем как их использовать

Ну буду я проверять .... и чего ???
обьект-то убит :(((
а вечное пересоздание самого себя так это рекурсия и всё-такое прочее, опять флажки вешать :(

короче нормального решения нет :(((((
буду плакать и страдать...


 
z0ne   (2005-08-18 16:47) [9]

нет у нас согласия ......

Иду я с пивом и думаю щас допью и обоссусь.
что делать ???

вы мне советуете: как начнёшь ссацца - проверь пил ли ты пиво!

а мне надо: не пить пиво!

собственно вот.
засим, наверное, прощщевайте. пойду куличики лепить.
Завтра может загляну ещё раз. на всякий случай ;)


 
Reindeer Moss Eater ©   (2005-08-18 17:17) [10]

компонент который "должен жить" это прослойка в наследнике от TDataSet которая отвечает за работу с конкретным SQLСервером соответственно черезнего работают все запросы типа StartTransaction, ExecSQL, SELECT ну и прочие.
на него опирается ещё пара-тройка компонент, которые хотят общаться с базой.


Обычно в таких случаях эти компоненты, "которые должны жить" оформляются не как компоненты, а просто как классы.
Например для каждого специфичного сервера рисуется модуль со специфичным для модуля классом. В intialization этого модуля этот класс регистрируется в списке всех доступных серверов.
А общий T_DataSet, который ничего не знает о конкретном сервере работает именно через эти зарегистрированные фичи для конкретного сервера.

Хороший пример реализации подобной схемы можно найти в EhLib"е (каталог DataServices). Там для работы грида используется именно такой механизм.
Причем за убийством нужных компонентов следить не надо, так как их нет. Есть экземпляры классов, создаваемые если соотв. модуль есть в uses проекта.


 
z0ne   (2005-08-18 17:48) [11]

о !!!
а это хорошая идея !!!
..
хотелось бы конечно визуальности ... но это мы обернём :)
ОГРОМНОЕ ЧЕЛОВЕЧЕСКОЕ СПАСИБО


 
Reindeer Moss Eater ©   (2005-08-18 18:08) [12]

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

TSomeServerFeatures = class(TComponent)
end;

Компонент регистрируется в палитре.
Все кто его помещают на форму получают в uses имя нужного модуля и соответственно получают функциональность для нужного сервера.


 
Юрий Зотов ©   (2005-08-18 19:06) [13]

Еще вариант - интерфейс. Подсчет ссылок - автоматический, самоубийство - тоже.


 
Наиль ©   (2005-08-18 20:57) [14]

>[6] и [10]
Не знаю почему, но мне это жутко напоминает TSession и TDataBase.
Существуют, даже если компонента на форму не брошена. Но если уж брошена, то можно поуправлять.


 
z0ne   (2005-08-19 09:39) [15]

как грится все идеи хороши - выбирай на вкус
всем спасибо!
по итогам обсуждения приняты вырианты:
1. компонента - пустышки
2. интерфейс
3. в Create(!) вечноживущего компонента при его создании в run-time AOwner заменяется на Application :) или AOwner.Owner. ... .Owner.


 
z0ne   (2005-08-23 10:15) [16]

если кому ещё интересно :))))
всё решилось так:

1. в Create
[Code]
If (not (csDesignins in ComponentState)) and
  (AOwner<>NIL)
then FreeNotinication(AOWner)
[/Code]

2. в Notifycation
[Code]
If (AComponent=Owner) and (Operation=opRemove)
then begin
 RemoveFreeNotifycation(Owner) // ??? не помню, вродебы так
 Owner.RemoveComponent(Self);
 Application.InsertComponent(Self);
end;
[/Code]


 
Юрий Зотов ©   (2005-08-23 13:43) [17]

В таком случае почему бы вместо всего этого сразу не написать в конструкторе inherited Create(Application)?


 
z0ne   (2005-08-24 16:44) [18]

а потому что другие компоненты на DataSource, которые привязятись  к "живчику" у disign-time при загрузке ищут его в Owner.Components ... а мы его засандалили к Application ...



Страницы: 1 вся ветка

Текущий архив: 2006.02.12;
Скачать: CL | DM;

Наверх




Память: 0.52 MB
Время: 0.052 c
2-1137888484
Dormidont
2006-01-22 03:08
2006.02.12
Функция Undo текстового редактора


2-1138038072
WST
2006-01-23 20:41
2006.02.12
-= Версия файла =-


15-1137954001
iZEN
2006-01-22 21:20
2006.02.12
Инструментарий для исследования, анализа IP-пакетов.


2-1138030902
Коля
2006-01-23 18:41
2006.02.12
Куда посоветуете спрятать пароль?


2-1138273981
CyMKuH
2006-01-26 14:13
2006.02.12
Как "вырвать" иконку из DLL и сохранить в "*.ico"