Very un-snappy title I know.
I have a series of text lines that I need to perform certain operations on in a certain order. I have come up with a means of doing this by defining the following record structure:
TProcessOrderRecord = record
RecordTypes: TByteSet;
InitialiseProcedure: TPreScanProc;
ProcessProcedure: TProcessRecord;
FinaliseProcedure: TEndScanProc;
end;
AProcessOrderArray = array of TProcessOrderRecord;
Initialise tends to call a constructor which will fill a field in the host object.
Process will be a procedure on the object which will be called for each text line that matches one of the record types in RecordTypes.
Finalise will tend to call the destructor and possibly do any checks when it knows that the full set of records has been processed.
The means of processing this array is quite straightforward:
procedure TImport.ScanTransferFile;
var
i: integer;
lArrayToProcess: AProcessOrderArray;
begin
lArrayToProcess := SetUpProcessingOrder(NLPGApp.ImportType);
for i := low(lArrayToProcess) to high(lArrayToProcess) do
begin
ProcessRecordType(lArrayToProcess[i].RecordTypes, lArrayToProcess[i].InitialiseProcedure, lArrayToProcess[i].ProcessProcedure, lArrayToProcess[i].FinaliseProcedure);
end;
end;
procedure TImport.ProcessRecordType(const RecordTypesToFind: TByteSet; PreScanProcedure: TPreScanProc; OnFindRecord: TProcessRecord; OnCompleteScan: TEndScanProc);
var
lLineOfText: string;
lIntegerRecordID: byte;
begin
if Assigned(PreScanProcedure) then PreScanProcedure;
try
if assigned(OnFindRecord) then
begin
Reader.GoToStartOfFile;
while not Reader.EndOfFile do
begin
lLineOfText := Reader.ReadLine;
lIntegerRecordID := StrToIntDef(GetRecordID(lLineOfText), 0);
if lIntegerRecordID in RecordTypesToFind then
begin
try
OnFindRecord(lLineOfText);
except
on E: MyAppException do
begin
// either raise to exit or log and carry on
end;
end;
end;
end;
end;
finally
// OnCompleteScan usually contains calls to destructors, so ensure it's called
if Assigned(OnCompleteScan) then OnCompleteScan;
end;
end;
My problem is that I want to define a record as such:
RecordTypes = [10]
InitialiseProcedure = ProcToCreateFMyObj
ProcessProcedure = FMyObj.do
FinaliseProcedure = ProcToFreeFMyObj
This compiles fine, however when ProcessProcedure is called, as FMyObj was nil when the ProcessProcedure is set, the instance of TMyObj is nil even though FMyObj is now set. Is there any clean way to get the record to point to the instance of FMyObj at the time of calling rather than at the time of first assignment?
At present I have resorted to having 'caller' methods on the host object which can then call the FMyObj instance when needed, but this is creating quite a bloated object with lots of single-line methods.
Edit to clarify/complicate the problem
Sometimes one instance of FObj
can handle more than one types of record (usually if they have a master-detail relationship). In this case, InitialiseProcedure
of the first record type will create FObj
, FinaliseProcedure
of the second record will free FObj
and each record's ProcessProcedure
can reference different procedures of FObj
(do1
and do2
).