На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! ПРАВИЛА РАЗДЕЛА · FAQ раздела Delphi · Книги по Delphi
Обязательно выделяйте текст программы тегом [сode=pas] ... [/сode]. Для этого используйте кнопку [code=pas] в форме ответа или комбобокс, если нужно вставить код на языке, отличном от Дельфи/Паскаля.

Этот раздел предназначен для вопросов, посвященных разработке компонентов, а также для тестирования собственных бесплатных компонентов с открытым исходным кодом.

Здесь запрещается:
1. Размещать ссылки на какие-либо коммерческие компоненты, реализующие требуемую функциональность.
2. Обсуждать и тестировать коммерческие компоненты или компоненты с закрытым кодом.
3. Давать ссылки на сайты с исходным кодом компонентов. Все тестируемые исходные коды должы быть размещены на сайте ИСХОДНИКИ.RU.
Модераторы: Rouse_, DimaBr
Страницы: (2) [1] 2  все  ( Перейти к последнему сообщению )  
> Как уничтожить TDatamodule
    Решил создать для себя класс для того чтобы скрыть в приложении детали соединения и общения с базой. Для этого создаю :
    ExpandedWrap disabled
      unit baseconnector;
       
      interface
      uses rwindows,forms,sysutils,classes,IBDatabase, DB, IBCustomDataSet, IBQuery,
      datamodule1 ;
      type
       TBaseConnector= class
       
      private
       
      public
      app2:TApplication;
      constructor Create(app:TApplication);
       destructor Destroy; override;
      function getallparameters(groupid:integer;parnamelist,parvallist,pargrouplist:tstringlist):integer;
       
      end;
       
      implementation
       
       constructor TBaseConnector.Create(app:TApplication);
       begin
         app.CreateForm(TDataModule2, DataModule2);
         app2:=app;
       end;
       
       destructor TBaseConnector.Destroy;
      begin
      //dATAMODULe2.DestroyComponents;
      //  Datamodule2.Free;//ошибка Invalid Pointer Operation
       
       
       
        inherited;
      end;
       
       
       
      end.


    Не знаю, может делаю через задницу но для того чтобы не париться с ручным созданием IBDatabase, Ibtransaction и т.д ... решил использовать tdatamodule чтобы накидать туда компонентов а его уже юзать через TBaseConnector.

    ExpandedWrap disabled
      unit datamodule1;
       
      interface
       
      uses
        SysUtils, Classes, IBDatabase, DB, IBCustomDataSet, IBQuery;
       
      type
        TDataModule2 = class(TDataModule)
          IBDatabase1: TIBDatabase;
          IBTransaction1: TIBTransaction;
          IBQuery1: TIBQuery;
          IBDataSet1: TIBDataSet;
        private
          { Private declarations }
        public
          { Public declarations }
        
        end;
       
      var
        DataModule2: TDataModule2;
       
      implementation
       
      {$R *.dfm}
       
       
       
      end.

    Вопрос в том как уничтожить экземпляр Datamodule2?
      TBaseConnector сделай интерфейсом, в дата модуле реализуй его...
        Цитата cyberovskij @
        Datamodule2.Free;//ошибка Invalid Pointer Operation

        Потому что он в этот момент уже уничтожен.
        1) для того что бы узнать что компонент уничтожается у TCompenent есть событие Notification
        2) компонент автодеструктурируется если уничтожается его владелец. (в данном случаи его владельцем будет app: TApplication).
        3) нафзачем тебе переменная app2:TApplication? то есть ты не можешь заглянуть в модуль forms и взять ее там?
          Цитата ViktorXP @
          3) нафзачем тебе переменная app2:TApplication? то есть ты не можешь заглянуть в модуль forms и взять ее там?

          А хр не знаю
            Цитата cyberovskij @
            Не знаю, может делаю через задницу но для того чтобы не париться с ручным созданием IBDatabase, Ibtransaction и т.д ... для того чтобы скрыть в приложении детали

            Не сомневайся, именно так ты и поступаешь.
            Ну и что такого сложного: задать имя базы данных.
              Цитата 05772 @
              Ну и что такого сложного: задать имя базы данных.

              Может и действительно ничего сложного для ( нескольких_database+ нескольких_ibtransaction+ нескольких_десятков_датасетов)*нескольких_десятков_дефолтных_значений.
                А зачем уничтожать датамодуль, скажи, пожалуйста. Сильно мешает?
                  Цитата Fr0sT @
                  А зачем уничтожать датамодуль, скажи, пожалуйста. Сильно мешает?

                  А зачем освобождают ненужные ресурсы?
                    cyberovskij так он у тебя нормально при выгрузке приложения освободится и без твоего участия. Зачем это делать руками?
                      Но если надо ручками тоже можно. А почему бы и нет?
                      Надо просто отслежитвать корректно освобождение "старндартной" var DataModule2.
                      Например, таким макаром:
                      ExpandedWrap disabled
                        unit datamodule1;
                         
                        type
                           TDataModule2 = class   // (?) странно что в Unit "DataModule1" находится TDataModule2, может быть их сделать с одинаковыми номерами?
                           ...
                           public
                           ...
                               destructor Destroy; override;
                           end;
                        ...
                         
                        var
                          DataModule2: TDataModule2;
                         
                        implemenation
                        ...
                         
                        destructor TDataModule2.Destroy;
                        begin
                           if Self = DataModule2 then DataModule2 := nil;
                           inherited;
                        end;
                         
                        ...
                        end.

                      а освообождение выполнять не "диким" способом

                      ExpandedWrap disabled
                         DataModule2.Free;
                      :o :no:

                      а аккуратно:
                      ExpandedWrap disabled
                         FreeAndNil(DataModule2);

                      чтобы в случае, когда DataModule2 уже почил, не получить "NULL Pointer Exception"
                      ;)
                        Цитата RuSA @
                        Надо просто отслежитвать корректно освобождение "старндартной" var DataModule2.

                        более безопаснее будет заюзать Notification. да и более удобно. можно выполнить какое то действие в сам момент уничтожения
                          Если юзать FreeAndNil, то if Self = DataModule2 then DataModule2 := nil; - излишне
                            Совсем нет.

                            Цитата Fr0sT @
                            Если юзать FreeAndNil, то if Self = DataModule2 then DataModule2 := nil; - излишне

                            Наличие проверки в деструкторе, гарантирует очистку становящейся некорректной var-переменной. Ведь никто не гарантирует, что все виды освобождений будут проходить именно через FreeAndNil !?

                            Цитата ViktorXP @
                            более безопаснее будет заюзать Notification. да и более удобно. можно выполнить какое то действие в сам момент уничтожения

                            Интересно чем безопаснее?
                            Завязка на Notification нужна там, где вводится синоним. Прич1м изящно это можно сделать, если класс обладатель синонима будет потомком TComponent (у которого есть Notification).

                            Т.е. если бы в модуле TBaseConnector была своя копия указателя, то тогда надо было бы иметь Notification.
                            Т.е. примерно так:
                            ExpandedWrap disabled
                              type
                                 TBaseConnector = class(TComponent)
                                 ...
                                 private
                                    FDM: TDataModule2;
                                    ...
                                    procedure setDM( adm: TDataModule2);
                                    ...
                                 protected    
                                    ...
                                    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
                                 ...
                                 public
                                    property DM: TDataModule2 read FDM write setDM;
                                 end;
                               
                              implementation
                               
                              ...
                               
                              procedure TBaseConnector.Notification(AComponent: TComponent; Operation: TOperation);
                              begin
                                 inherited;
                                 if Operation = opRemove then
                                 begin
                                    if AComponent = Self.FDM then Self.FDM := nil;
                                 end;
                              end;
                               
                              procedure TBaseConnector.setDM( adm: TDataModule2);
                              begin
                                 if (FDM <> adm) then
                                 begin
                                    FDM := adm;
                                    if (adm <> nil) then adm.FreeNotofication(Self);
                                 end;
                              end;
                               
                              ...
                              end.

                            Такой метод применять для самого TDataModule очевидно, слишком длино.
                            В деструкторе это смотрится гораздо логичнее, тем более что DataModule2 это unit-перменная, а не поле экземпляра класса (instance-field).
                              Цитата RuSA @
                              Интересно чем безопаснее?

                              никогда не нарвешся на мертвую ссылку. и тогда даже задумываться не будешь насчет
                              Цитата RuSA @
                              Наличие проверки в деструкторе, гарантирует очистку становящейся некорректной var-переменной. Ведь никто не гарантирует, что все виды освобождений будут проходить именно через FreeAndNil !?


                              пс. и его вообще можно конструировать в этом контейнере по запросе.
                                Честно говоря думая что я не докнца понял что Вы хотели сказать, но вот есть такие соображения:
                                1) FreeAnlNil(X) удобнее простого X.Free вот чем:
                                а) если освобождаемая переменная X уже nil, то FreeAndNil выполнится без ошибок, а Free даст "NULL Pointer",
                                б) после выполнения освобождения, надо очичать X, иначе там останется "битая ссылка". FreeAndNil после своего выполнения выставит nelf nil, Free - нет.
                                в) если перед выполнением операций в X уже ссылка битая (т.е. X <> nil, но сама перменная освобождена), оба варианта дадут нерпедсказуемые проблемыи в этом они схожи.

                                2) по-поводу
                                никогда не нарвешся на мертвую ссылку

                                Цитата ViktorXP @
                                никогда не нарвешся на мертвую ссылку

                                это слишком громко сказано, т.к. в достаточно большом или старом проекте, нельзя гарантировать, что использования всегда будут "академически правильными". Так что простые "FreeAnNil", как показывает практика, достаточно просто позволят локализовать подобные ошибки.
                                И вопрос корректного отслеживания ссылок в языках с отсутствием встроенного "сборщика мусора" вообще большая проблема.
                                Вариант с обычным Notification проходит удобно только для синонимов внутри классов-потомков TCompoment, для других классов надо в каждом случае думать как это сделать безопасно.

                                В исходном варианте проблема была в том, что в момент вызова
                                ExpandedWrap disabled
                                   Datamodule2.Free;//ошибка Invalid Pointer Operation
                                Datamodule2 была <> nil, но сам экземпляр уже был освобождён. Так что вариант с обнулением в деструкторе вылечил бы это, если бы тут использовалось FreeAndNil.
                                Вот такие соображения.
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0473 ]   [ 17 queries used ]   [ Generated: 23.04.24, 13:48 GMT ]