powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Классовые конструкторы/деструкторы дженериков...
25 сообщений из 33, страница 1 из 2
Классовые конструкторы/деструкторы дженериков...
    #40012030
Фотография Virtual Student
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Добрый день всем!

Обнаружил, с неприятными для себя последствиями, что классовые конструкторы дженерик-классов вызываются каждый раз при динамической загрузке пакетов bpl ... Вызываются именно через инициализацию пакетов (LoadPackage).
Для обычных классов классовые конструкторы/деструкторы вызываются один раз, сколько раз не загружай/выгружай дополнительные пакеты.

Например, классовый конструктор приведенного ниже дженерик-класса будет вызван каждый раз , когда будем динамически грузить bpl.

Код: pascal
1.
2.
3.
4.
5.
6.
TIdComplex<T: class> = class(TIdCmpx, IIdComplex<T>)
...
  public
    class constructor Create;
    class destructor Destroy;
end;


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

Код: pascal
1.
2.
3.
4.
5.
6.
TIdComplexManager = class(TSingleton)
...
  public
    class constructor Create;
    class destructor Destroy;
end;


Подскажите, кто сталкивался.
Можно ли добиться от дженерик-классов стандартного поведения?
Если нет, то с чем это связано?
...
Рейтинг: 0 / 0
Классовые конструкторы/деструкторы дженериков...
    #40012041
SOFT FOR YOU
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Virtual Student,

Может конструктор дженерика вызывается для разных T?
...
Рейтинг: 0 / 0
Классовые конструкторы/деструкторы дженериков...
    #40012046
SOFT FOR YOU
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
По идее если пакет Foo использует дженерик<Integer> и пакет Bar использует дженерик<Integer> - он должен сконструироваться дважды. Дело в том, что обычный класс известный и его код попадает в пакет, где он объявлен. А вот дженерики могут быть преобразованы в бесконечное число типов. И они уже кладутся в тот пакет, где объявлены.

Если принципиально, что какая-то информация была уникальная для всех дженерик одного T - нужно на стороне главного модуля сделать синглетон от TypeInfo(T)
...
Рейтинг: 0 / 0
Классовые конструкторы/деструкторы дженериков...
    #40012047
Фотография Virtual Student
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SOFT FOR YOU
Virtual Student,

Может конструктор дженерика вызывается для разных T?


Для разных T, закономерно вызывается при загрузке основного пакета приложения. А потом, при каждой динамической загрузке/выгрузке пакетов, каждый раз дергает конструкторы/деструкторы всех дженерик-классов упоминаемых в загружаемом пакете . :(
Получается как бы, что для каждого динамического пакета инициализируется свой набор дженерик-классов...
Пробовал организовать RegisterClass не получается, т.к. жденерик-классы не унаследованы от TPresistent. Может есть другой путь?
...
Рейтинг: 0 / 0
Классовые конструкторы/деструкторы дженериков...
    #40012051
Фотография Virtual Student
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SOFT FOR YOU

Если принципиально, что какая-то информация была уникальная для всех дженерик одного T - нужно на стороне главного модуля сделать синглетон от TypeInfo(T)

Можно поподробнее или где-то почитать!?
...
Рейтинг: 0 / 0
Классовые конструкторы/деструкторы дженериков...
    #40012055
SOFT FOR YOU
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Можно вообще сделать с подсчётом ссылок :)

var
D: TDictionary<PTypeInfo,Integer>;

procedure Register(I: PTypeInfo);
begin
if D.TryGetValue(I, Count) then
D[I] := Count + 1
else
begin
D.Add(I, 1);
InternalConstruct(I);
end;

Ну что-то типа такого. И Unregister по аналогии. С мобилы просто пишу )
...
Рейтинг: 0 / 0
Классовые конструкторы/деструкторы дженериков...
    #40012060
Фотография Virtual Student
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SOFT FOR YOU,

Это не совсем то, чего мне нужно добиться...
При объявлений дженерика, генерируется новый класс. Я пытаюсь использовать это для общих полей, так сказать
Код: pascal
1.
class var virtual Catalog: TCatalog;


чтобы каждый унаследованный класс-дженерик имел свой набор вложенных объектов .
Подход работает, но только в рамках главного пакета приложения. А динамическая загрузка/выгрузка доп. пакетов все портит на корю...
...
Рейтинг: 0 / 0
Классовые конструкторы/деструкторы дженериков...
    #40012064
DimaBr
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
A class constructor is a special class method that is not accessible to developers.
Calls to class constructors are inserted automatically by the compiler into the initialization section of the unit where the class is defined
Вызов классового конструктора автоматически помещается в секцию initialization.
При подключении пакета вызывается секция initialization.
...
Рейтинг: 0 / 0
Классовые конструкторы/деструкторы дженериков...
    #40012066
SOFT FOR YOU
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Virtual Student,

А ты хочешь чтобы при компиляции главного пакета в него попадали классы, о которых он не знает? )
...
Рейтинг: 0 / 0
Классовые конструкторы/деструкторы дженериков...
    #40012094
Фотография Virtual Student
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SOFT FOR YOU
Virtual Student,

А ты хочешь чтобы при компиляции главного пакета в него попадали классы, о которых он не знает? )


Нет. Я хочу, чтобы дженерик-классы не проходили заново инициализацию при динамической загрузке пакетов. По тому, что их классовые переменные можно использовать вместо глобальных объектов. Например прописать в классовые переменные каталоги, справочники, нулевые элементы и т.п...
...
Рейтинг: 0 / 0
Классовые конструкторы/деструкторы дженериков...
    #40012110
L_argo
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Например прописать в классовые переменные каталоги, справочники интересно, о чем тут идет речь ?
...
Рейтинг: 0 / 0
Классовые конструкторы/деструкторы дженериков...
    #40012158
Фотография X-Cite
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Virtual Student,

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

т.е. в RTTI вы не увидите TIdComplex<> и не сможете построить дженерик или выделить подкласс, как это сделано в .Net
Вместо этого вы увидите TIdComplex<A> TIdComplex<B> TIdComplex<C> а это по сути 3 класса.

Эту проблему можно решить через синглтон
...
Рейтинг: 0 / 0
Классовые конструкторы/деструкторы дженериков...
    #40012184
SOFT FOR YOU
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Virtual Student,

Ну так я же сказал, как это сделать
...
Рейтинг: 0 / 0
Классовые конструкторы/деструкторы дженериков...
    #40012271
Фотография Virtual Student
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
X-Cite
Virtual Student,
Вместо этого вы увидите TIdComplex<A> TIdComplex<B> TIdComplex<C> а это по сути 3 класса .

Это меня как раз и устраивает! И этим пользуюсь создавая по сути в каждом классе свои, общие для конкретного дженерик-класса , необходимые мне структуры (например, каталог единиц измерения для мат. расчетов в самом классе единицы измерения TUnit).
Моя проблема в том, что в динамически загружаемых пакетах, я вижу вместо этих структур - nil ...
Внутри основного пакета (ядра) все прекрасно работает, а также для некоторых случаев загрузки ссылки сохраняются (это чистая случайность).

Реализовал костыль с глобальным управлением этими ресурсами. Но мне не нравиться, что для поиска по каталогу, мне нужно перед этим искать сам каталог по соответствию нужному классу в словаре...
...
Рейтинг: 0 / 0
Классовые конструкторы/деструкторы дженериков...
    #40012272
Фотография Virtual Student
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
L_argo
Например прописать в классовые переменные каталоги, справочники
интересно, о чем тут идет речь ?
Каталоги, данные которых постоянно нужны в формах и отчетах. Например справочник "единицы измерения", содержащий коды красивой (с индексами пр...) отрисовки единиц измерения в таблицах, деревьях и отчетах. Или виды операций со значками и самими операторами.
...
Рейтинг: 0 / 0
Классовые конструкторы/деструкторы дженериков...
    #40012273
Фотография X-Cite
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Virtual Student,

Если в динамических пакетах эти классы только описаны - нет экземпляров классов, то классовые конструкторы и деструкторы не будут вызваны.
Если вы создаете экземпляры через RTTI, не используя напрямую, токлассовые конструкторы и деструкторы тоже не будут вызваны.
...
Рейтинг: 0 / 0
Классовые конструкторы/деструкторы дженериков...
    #40012276
Фотография Virtual Student
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
X-Cite
Virtual Student,

Если в динамических пакетах эти классы только описаны - нет экземпляров классов, то классовые конструкторы и деструкторы не будут вызваны.

В динамических пакетах эти классы только используются... Никаких новых экземпляров таких классов не создается.
...
Рейтинг: 0 / 0
Классовые конструкторы/деструкторы дженериков...
    #40012291
Fr0sT-Brutal
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
А что, bpl-и прям в рантайме постоянно грузятся-выгружаются?
...
Рейтинг: 0 / 0
Классовые конструкторы/деструкторы дженериков...
    #40012293
Фотография X-Cite
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Логично, что если вы выгрузили пакет, то при выгрузке вызывается финализация всего, что было в пакете в т.ч. и глобальные переменные, коими и являются классовые переменные...
Когда вы загружаете пакет, то они соответственно инициализируются...
...
Рейтинг: 0 / 0
Классовые конструкторы/деструкторы дженериков...
    #40012305
Фотография Virtual Student
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
X-Cite
Логично, что если вы выгрузили пакет, то при выгрузке вызывается финализация всего, что было в пакете в т.ч. и глобальные переменные, коими и являются классовые переменные...
Когда вы загружаете пакет, то они соответственно инициализируются...

Я ж говорю, - гранаты не той системы. :)

exe <->
kernel.bpl ( здесь лежат дленерик-классы , да и вообще вся бизнес-логика приложения)
<-> form1.bpl
<-> form2.bpl
...
<-> formN.bpl

kernel.bpl грузиться вместе с exe .
При разных пользовательских действиях из БД (online/onklick система обновления) подгружаются нужные редакторы (пакеты), админки, логилки и т.п. из пакетов formN.bpl
Формы из пакетов formN.bpl работают с данными и структурами, загружаемыми в kernel.bpl .

Загружая/выгружая пакет формы formN.bpl я не ожидаю, что мои дженерик-классы будут инициализироваться/финализироваться заново. При этом, обычные классы инициализируются/финализируются штатно , т.е. при загрузке/выгрузке пакета ядра kernel.bpl , а не в коем случае при загрузке/выгрузке динамических пакетов...

Вот что я пытаюсь разрулить...
...
Рейтинг: 0 / 0
Классовые конструкторы/деструкторы дженериков...
    #40012307
Фотография Virtual Student
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
К стати, пробовал грузить blp-ки без инициализации (LoadLibrary).
Инициализация не происходит, но ссылки бьются... :(
...
Рейтинг: 0 / 0
Классовые конструкторы/деструкторы дженериков...
    #40012308
Kazantsev Alexey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Virtual Student
kernel.bpl ( здесь лежат дленерик-классы , да и вообще вся бизнес-логика приложения)

Если под этим имеется ввиду, что тут описаны классы:
Код: pascal
1.
2.
3.
TMyClass<T>=class
...
end;


Virtual Student
Формы из пакетов formN.bpl работают с данными и структурами, загружаемыми в kernel.bpl .

А тут они используются:
Код: pascal
1.
var mc : TMyClass<TSomeType>;


То описываемое поведение корректно т.к. дженерик обретает "физическую форму" в момент конкретизации/специализации.

Что с этим делать. В основном пакете подготовить все необходимые типы:
Код: pascal
1.
2.
3.
4.
type
 TMyClassWithByte = TMyClass<Byte>;
 TMyClassWithString = TMyClass<String>;
 TMyClassWithSomeType = TMyClass<SomeType>;


В дочерних пакетах использовать только этот набор.
...
Рейтинг: 0 / 0
Классовые конструкторы/деструкторы дженериков...
    #40012317
Фотография Virtual Student
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
[quot Kazantsev Alexey#22221616]
Virtual Student

Что с этим делать. В основном пакете подготовить все необходимые типы:
Код: pascal
1.
2.
3.
4.
type
 TMyClassWithByte = TMyClass<Byte>;
 TMyClassWithString = TMyClass<String>;
 TMyClassWithSomeType = TMyClass<SomeType>;


В дочерних пакетах использовать только этот набор.

Да. Так оно везде и сделано!
Эффект сохраняется... Но инициализируются не TMyClassWithByte и TMyClassWithString, а TMyClass<Byte> и TMyClass<String>.
Наследование дженериков у нас организовано значительно сложнее...

Например:

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
// Часть описания дженерик-классов
IIdComplex<T: class> = interface
TModObject = class(TSingleton, IModObserver, IModNotify)
TModObjectList<T: class> = class(TObjectList<T>, IModObserver, IModNotify, IModObjectList, IPrintString)
TIdCmpx = class(TId, IIdCmpx, IXMLObjectId, IXMLIdComplex, IPrintString)
TIdComplexDictionary<T: class; I: IIdComplex<T>> = class(TObjectDictionary<TIdCmpxKey, TIdComplex<T>>)
TModComplexList<T: class> = class(TModObjectList<T>)
TIdComplexList<T: class> = class(TObjectList<TIdComplex<T>>)

TIdComplexController<T: class; I: IIdComplex<T>> = class(TModObjectList<T>)
  property IdList: TIdComplexList<T: class>;  // список Id элементов
  property Dictionary: TIdComplexDictionary<T: class; I: IIdComplex<T>>; // словарь для быстрого доступа
end;

TIdComplex<T: class> = class(TIdCmpx, IIdComplex<T>)
  property Null: TComplexObject<T: class>;  // "Нулевой" элемент (при поиске, вместо nil)
  property Catalog: TIdComplexController<T: class; I: IIdComplex<T>>;  // Этот каталог мы используем везде...
end;

TComplexObject<T: class> = class(TModObject, IId, IIdComplex<T>, IIdCmpxGate)
public
  property Id: TIdComplex<T: class>;  // идентификатор объекта (может быть длинным и сложным)
end;

// Дальше идет реализация конкретных классов приложения

TIdOrg = class(TIdComplexCatalog<TOrg>)
... // данные конкретного идентификатора
end;

TOrg = class(TComplexObject<TOrg>, IModInfo, IXMLObject, IDataSetObject)
... // данные конкретного класса (элемента)
end;


В нашем случае повторно инициализируются классы типа TComplexObject<TOrg> и т.п...
Есть подозрения, что все проблемы от конструкции наследования самого от себя, как сделан TOrg...
...
Рейтинг: 0 / 0
Классовые конструкторы/деструкторы дженериков...
    #40012319
rgreat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Virtual Student,

И зачем было делать так сложно?
...
Рейтинг: 0 / 0
Классовые конструкторы/деструкторы дженериков...
    #40012320
rgreat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
...
Рейтинг: 0 / 0
25 сообщений из 33, страница 1 из 2
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Классовые конструкторы/деструкторы дженериков...
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]