Създайте TDataModule само веднъж

Опитвам се да създам procedure, който създава TDataModule в Application като свой родител.

Проблемът е, че вторият път, когато извикам procedure, параметърът dm все още е nil. Очаквам нещо различно от nil като се има предвид, че е създаден преди.

Ето кода, който опитвам:

procedure UseDataModule(dm : TDataModule; cClass:TcomponentClass);
begin
    if dm = nil then
        cClass.Create(Application);
end;

Има някои изисквания, които искам за това procedure:

  1. Даденото TDataModule трябва да бъде създадено веднъж

  2. Трябва да се създаде от procedure, защото искам да го използвам понякога, затова не го поставям във формуляри за автоматично създаване

  3. Неговият родител винаги ще бъде Application

person WellingtonD    schedule 04.01.2019    source източник
comment
Пропускате да присвоите резултата от cClass.Create(Application) на каквото и да било. Ако искате резултатът да бъде присвоен на dm, тогава, както и вашият код, който прави действителното присвояване, dm трябва да бъде параметър var, в противен случай резултатът ще бъде отхвърлен след излизане на UseDataModule.   -  person MartynA    schedule 04.01.2019


Отговори (2)


Опитайте да промените кода си на този:

procedure UseDataModule(var dm : TDataModule; cClass:TcomponentClass);
//  the `var` qualifier is to allow the value of `dm` to be retained 
//  after `UseDataModule` exits, otherwise the Created instance will be discarded
//  and you will have a memory leak
begin
  if dm = nil then
    dm := cClass.Create(Application);
end;

Imo, би било по-добре да кодирате UseDataModule като функция, но това до голяма степен е въпрос на вкус. Имайте предвид също, че можете да напишете if notAssigned(dm) вместо if dm = Nil.

От вашия коментар разбирам, че сте решили да използвате следния код вместо първоначалното ми предложение:

  procedure UseDataModule(var dm : TDataModule; cClass:TcomponentClass);   
  begin 
    if dm = nil then begin 
      dm := cClass.Create(Application) as TDataModule; 
    end; 
  end;

което ми се струва добре.

person MartynA    schedule 04.01.2019
comment
dm = nil трябва да се замени с not assigned(), което е по-подробно - person whosrdaddy; 05.01.2019
comment
С уважение, не съм съгласен, трябва да е въпрос на лични предпочитания, imo. = Nil е прозрачен и самодокументиращ се, unassigned е непрозрачен и, както казвате, многословен.. - person MartynA; 05.01.2019
comment
Цел на Assigned: да провери дали методът/функцията е присвоен. Прочетете повече на: docwiki.embarcadero.com/Libraries/Tokyo/en/System. Възложено - person Zam; 06.01.2019
comment
@MartynA Благодаря ви за отговора. Направих малка промяна във вашия код, като прехвърлих създадения обект като TDataModule. Това е, което ми трябва. procedure UseDataModule(var dm : TDataModule; cClass:TcomponentClass); begin if dm = nil then begin dm := cClass.Create(Application) as TDataModule; end; end; Моля, променете кода си, за да мога да го приема като правилното решение - person WellingtonD; 07.01.2019
comment
Актуализирано, както е предложено. - person MartynA; 07.01.2019

Друг вариант е да използвате същия код, използван за автоматично създаване на формуляри с проверка дали вече е създаден.

  // Create data module if it doesn't already exist
  if DM = nil then Application.CreateForm(TDM, DM); 
person Brian    schedule 04.01.2019
comment
Благодаря ви за отговора. Опитах вашето решение преди и ми даде същия резултат. Параметърът DM продължава да е нула, независимо колко пъти извиквам процедурата. - person WellingtonD; 07.01.2019