powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Delphi [игнор отключен] [закрыт для гостей] / как задать конструктор записи по умолчанию?
19 сообщений из 19, страница 1 из 1
как задать конструктор записи по умолчанию?
    #39990137
GrigoriyFomin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Всем доброго вечера. Разбираюсь с методами записей - вещь вельми удобная и интересная, начал использовать ее для работы с БД. Но вот не могу разобраться. У меня уже немало кода используют локальные переменные-записи. недавно обнаружил, что объявленные локально в функциях/процедурах/событиях переменные-записи содержат внутри мусор, по моей логике работы с записями - не всегда все поля задаются явно по алгоритму, и не присвоенные в коде процедуры поля записи остаются непроинициализированные, соотв. с мусором. Так выявилась проблема, что поле типа TDateTime, которое не было присвоено в коде, при записи в БД вызывало арифметическую ошибку.
Суть проблемы - я так понял, нельзя задать свой дефолтный конструктор для записи. То есть задать во всех моих записях конструктор по умолчанию, чтоб он занулял все поля. Нужно добавить свой конструктор с каким-то параметром и потом перед использованием переменной-записи вызывать его явно в начале использования. (как-то сумбурно описал, но надеюсь вы смогли что-то понять). Грубо говоря - есть уже готовый код с использованием переменных-записей. Можно ли без добавления явного конструктора-обнулятора в каждом применении переменной-записи обнулить переменную-запись? Как я понял из документации - нельзя, но вдруг я плохой чукча-читатель?
Вот пример.
Код: 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.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
type
	TcfCash=record
    CID					:Int64;
    CFROM       :Int32;
    CTO         :Int32;
    CTYPE       :Int32;
    CPAYMENT    :Currency;
    CDATE       :TDateTime;
    CCAID       :Int32;
    CACCEPTED   :TDateTime;
    CCANCELED   :TDateTime;
    CCONFIRMED  :TDateTime;
    CVIEWED     :TDateTime;
    EMPID       :Int32;
    CDESCR      :string;
    CNO         :string;
    CDEST       :string;
    DBDATE      :TDateTime;
    CORDID      :Int64;
    CPARENT     :Int64;

    function 	 	AddCurrent(Atrs:TFDTransaction):Int64;
    function 	 	LoadToCurrent(ACID:Int64):boolean;
end;


////////////////////
function TcfCash.AddCurrent(Atrs:TFDTransaction):Int64;
var qw:TFDQuery;
begin
	qw:=TFDQuery.Create(nil);
	qw.Connection:=DM.conCF;
  qw.Transaction:=Atrs;
  qw.UpdateOptions.AutoCommitUpdates:=False;
  qw.UpdateTransaction:=Atrs;
  qw.SQL.Text:=
' insert into CASH (CFROM, CTO, CTYPE, CPAYMENT, CDATE, CCAID, CACCEPTED, CCANCELED, CCONFIRMED, CVIEWED, EMPID, CDESCR, '+
'                  CNO, CDEST, DBDATE, CORDID, CPARENT) '+
' values (:CFROM, :CTO, :CTYPE, :CPAYMENT, :CDATE, :CCAID, :CACCEPTED, :CCANCELED, :CCONFIRMED, :CVIEWED, :EMPID, :CDESCR, '+
'        :CNO, :CDEST, ''now'', :CORDID, :CPARENT) '+
' returning CID ';

	SetParamIfNot0(CFROM,				qw.ParamByName('CFROM'));
	SetParamIfNot0(CTO,					qw.ParamByName('CTO'));
  qw.ParamByName('CTYPE').AsInteger			:=CTYPE;
  qw.ParamByName('CPAYMENT').AsCurrency	:=CPAYMENT;
  qw.ParamByName('CDATE').AsDateTime		:=CDATE;
  qw.ParamByName('CCAID').AsInteger			:=CCAID;
  qw.ParamByName('EMPID').AsInteger			:=EMPID;
	SetParamIfNot0(CACCEPTED,		qw.ParamByName('CACCEPTED'));
	SetParamIfNot0(CCANCELED,		qw.ParamByName('CCANCELED'));
	SetParamIfNot0(CCONFIRMED,	qw.ParamByName('CCONFIRMED'));
	SetParamIfNot0(CVIEWED,			qw.ParamByName('CVIEWED'));
	SetParamIfNot0(CDESCR,			qw.ParamByName('CDESCR'));
	SetParamIfNot0(CNO,					qw.ParamByName('CNO'));
	SetParamIfNot0(CDEST,				qw.ParamByName('CDEST'));
	SetParamIfNot0(CORDID,			qw.ParamByName('CORDID'));
	SetParamIfNot0(CPARENT,			qw.ParamByName('CPARENT'));
  qw.active:=true;

  CID:=		qw.FieldByName('CID').AsLargeInt;
	result:=qw.FieldByName('CID').AsLargeInt;
	qw.Free;
end;


SetParamIfNot0 - это функция, которая очищает параметр (clear), если значение поля нулевое
Так вот, если я какое-то поле принудительно не зануля в своем коде - по умолчанию оно может быть совсем не нулевое и выходить за рамки сущности (как с датой - в поле TDateTime был мусор, который и не нулевой, и при записи в БД сыпал ошибку)
...
Рейтинг: 0 / 0
как задать конструктор записи по умолчанию?
    #39990142
Kazantsev Alexey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
GrigoriyFomin,

В 10.4 появилась возможность перегружать операторы инициализаци, финализации и присваивания:
Код: pascal
1.
2.
3.
class operator Initialize(out Value : TMyRec);
class operator Finalize(var Value : TMyRec);
class operator Assign(var Dst : TMyRec; const [ref] Src : TMyRec);
...
Рейтинг: 0 / 0
как задать конструктор записи по умолчанию?
    #39990146
GrigoriyFomin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Kazantsev Alexey
GrigoriyFomin,

В 10.4 появилась возможность перегружать операторы инициализаци, финализации и присваивания:
Код: pascal
1.
2.
3.
class operator Initialize(out Value : TMyRec);
class operator Finalize(var Value : TMyRec);
class operator Assign(var Dst : TMyRec; const [ref] Src : TMyRec);



на 10.4 смысла переходить пока не вижу - сыро и убого пока. А на более ранних получается нет возможности?
...
Рейтинг: 0 / 0
как задать конструктор записи по умолчанию?
    #39990152
Kazantsev Alexey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
GrigoriyFomin
А на более ранних получается нет возможности?

Без хаков - нет. С хаками, можно захучить продеруру InitializeRecord из system.pas, но решение так себе.
...
Рейтинг: 0 / 0
как задать конструктор записи по умолчанию?
    #39990189
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
GrigoriyFomin,
Лайфхак: добавьте в запись динамический массив и выставьте ему длину 1 элемент при обнулении полей. Далее проверяйте длину массива. Если массив пуст, значит работать нельзя.
...
Рейтинг: 0 / 0
как задать конструктор записи по умолчанию?
    #39990211
rgreat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Извратное, но рабочее, решение:

Можно сделать переменные рекорда приватными, доступ к ним организовать через проперти.
Дополнительно в рекорде добавить манаджед переменную (например строку).
И в геттере проверять на значение этой строки, если она пустая - инициализировать значения всх анманаджед переменных в рекорде. Ну и зачение строки менять на признак того что рекорд заинициализирован.
...
Рейтинг: 0 / 0
как задать конструктор записи по умолчанию?
    #39990234
Bred eFeM
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
GrigoriyFomin, хороший вопрос уже содержит ответ -
вызывать его явно в начале использования
или засплайсить/подменить InitializeRecord (да, лень она такая!)
Но, как говорят классики - нужно проверять входные значения на корректность (IsNan)
...
Рейтинг: 0 / 0
как задать конструктор записи по умолчанию?
    #39990275
Fr0sT-Brutal
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
rgreat
Извратное, но рабочее, решение:
Можно сделать переменные рекорда приватными, доступ к ним организовать через проперти.

Да нормальное решение.
...
Рейтинг: 0 / 0
как задать конструктор записи по умолчанию?
    #39990277
delphinotes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Переменные типа record, как и остальные "простые" переменные, требует явной инициализации (без которой в себе содержат мусор).

Если есть привычка обнулять локальные переменные простым присваиванием и нет желания дёргать спец.функцию инициализации, можно сделать, например так:

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
// глобальная переменная (можно спрятать в классе-хелпере)
var
  GZeroCash: TcfCash;

initialization
  // быстрое "обнуление" (можно вынести в класс-конструктор хелпера)
  ZeroMemory(@GZeroCash, SizeOf(GZeroCash));

// где-то в коде:
  // инициализация простым присваиванием
  MyCash := GZeroCash;
  // и далее работа
  MyCash.CID := ...;
...
Рейтинг: 0 / 0
как задать конструктор записи по умолчанию?
    #39990304
Мимопроходящий
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
delphinotes, F1: Declaring variables
...
Рейтинг: 0 / 0
как задать конструктор записи по умолчанию?
    #39990314
alekcvp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
delphinotes

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
// глобальная переменная (можно спрятать в классе-хелпере)
var
  GZeroCash: TcfCash;

initialization
  // быстрое "обнуление" (можно вынести в класс-конструктор хелпера)
  ZeroMemory(@GZeroCash, SizeOf(GZeroCash));

// где-то в коде:
  // инициализация простым присваиванием
  MyCash := GZeroCash;
  // и далее работа
  MyCash.CID := ...;


Код: pascal
1.
2.
  MyCash := Default(TcfCash);
  MyCash.CID := ...;
...
Рейтинг: 0 / 0
как задать конструктор записи по умолчанию?
    #39990322
Фотография makhaon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
delphinotes,

так лучше:

Код: pascal
1.
 GZeroCash := Default(TcfCash);
...
Рейтинг: 0 / 0
как задать конструктор записи по умолчанию?
    #39990325
alekcvp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
makhaon
delphinotes,

так лучше:
Код: pascal
1.
 GZeroCash := Default(TcfCash);


И зачем вообще эта прокладка нужна?..
...
Рейтинг: 0 / 0
как задать конструктор записи по умолчанию?
    #39990330
Фотография makhaon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
alekcvp,

какая прокладка?

Код: pascal
1.
2.
3.
// глобальная переменная (можно спрятать в классе-хелпере)
var
  GZeroCash: TcfCash;
...
Рейтинг: 0 / 0
как задать конструктор записи по умолчанию?
    #39990339
alekcvp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
makhaon
alekcvp,
какая прокладка?

Он эту переменную создал чтобы её обнулить и присваивать её нормальным. Зачем так делать, если можно обнулять сразу нужные?
...
Рейтинг: 0 / 0
как задать конструктор записи по умолчанию?
    #39990340
Fr0sT-Brutal
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
alekcvp
Он эту переменную создал чтобы её обнулить и присваивать её нормальным. Зачем так делать, если можно обнулять сразу нужные?

После появления Default не нужно. Это прием из старой школы.
...
Рейтинг: 0 / 0
как задать конструктор записи по умолчанию?
    #39990369
Фотография makhaon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
alekcvp,

не понял о чем речь. вот глобальная переменная:

Код: pascal
1.
2.
3.
// глобальная переменная (можно спрятать в классе-хелпере)
var
  GZeroCash: TcfCash;



ее нужно очищать. и лучше это делать как Default, а не как ZeroMemory. какая прокладка?
...
Рейтинг: 0 / 0
как задать конструктор записи по умолчанию?
    #39990370
Мимопроходящий
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ГЛОБАЛЬНЫЕ переменные очищать НЕ НУЖНО!
RTFM уже в конце концов.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
как задать конструктор записи по умолчанию?
    #39990407
alekcvp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
makhaon
alekcvp,

не понял о чем речь. вот глобальная переменная:
ее нужно очищать. и лучше это делать как Default, а не как ZeroMemory. какая прокладка?

Ему нужно очищать локальные переменные, а не глобальные. И он делает это присваивая им пустую глобальную переменную , т.е. прокладку.
...
Рейтинг: 0 / 0
19 сообщений из 19, страница 1 из 1
Форумы / Delphi [игнор отключен] [закрыт для гостей] / как задать конструктор записи по умолчанию?
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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