如何在对象存在之前将记录字段设置为“对象的过程”以便它可以运行

时间:2013-03-06 17:18:44

标签: delphi delphi-2006

我知道非常不爽的标题。

我有一系列文本行,我需要按特定顺序执行某些操作。通过定义以下记录结构,我想出了一种方法:

TProcessOrderRecord = record
  RecordTypes:       TByteSet;
  InitialiseProcedure: TPreScanProc;
  ProcessProcedure:    TProcessRecord;
  FinaliseProcedure:   TEndScanProc;
end;

AProcessOrderArray = array of TProcessOrderRecord;

Initialise倾向于调用构造函数来填充宿主对象中的字段。

进程将是对象的一个​​过程,将为每个与RecordTypes中的一个记录类型匹配的文本行调用。

Finalize将倾向于调用析构函数,并且当它知道已处理完整的记录集时可能会进行任何检查。

处理这个数组的方法非常简单:

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;

我的问题是我想要定义一条记录:

RecordTypes = [10]
InitialiseProcedure = ProcToCreateFMyObj
ProcessProcedure = FMyObj.do
FinaliseProcedure = ProcToFreeFMyObj

这编译很好,但是当调用ProcessProcedure时,因为当设置ProcessProcedure时FMyObj为nil,即使现在设置了FMyObj,TMyObj的实例也为零。是否有任何干净的方法让记录在调用时指向FMyObj的实例,而不是在第一次分配时?

目前我已经在主机对象上使用'caller'方法,然后可以在需要时调用FMyObj实例,但是这会创建一个包含大量单行方法的非常臃肿的对象。

编辑以澄清/使问题复杂化

有时,FObj的一个实例可以处理多种类型的记录(通常如果它们具有主 - 细节关系)。在这种情况下,第一个记录类型的InitialiseProcedure将创建FObj,第二个记录的FinaliseProcedure将免费FObj,每个记录的ProcessProcedure可以引用不同的程序FObjdo1do2)。

2 个答案:

答案 0 :(得分:3)

  

目前我已经在主机对象上使用'caller'方法,然后可以在需要时调用FMyObj实例,但是这会创建一个包含大量单行方法的非常臃肿的对象。

这是正确的解决方案。由于实例在初始化时不可用,因此您没有其他选择。

当您使用of object时,您正在定义名为method pointer的内容。分配给方法指针类型的变量时,将在赋值点捕获实例。没有与动态解析方法指针关联的实例的机制。实现这一目标的唯一方法是使用运行时委派,这是您当前正在执行的操作。通常情况下,使用另一层间接来解决问题!

包含多种方法的记录看起来非常像interface。我怀疑最优雅的解决方案将涉及interface。也许在调用时你可以调用一个返回interface的函数。并且该函数将在调用时使用FMyObj的值来定位适当的接口。

答案 1 :(得分:1)

是的,可以对记录进行额外的运行时初始化:

var
  A: TProcessOrderRecord;

begin
  ..
  TMethod(A.ProcessProcedure).Data:= FMyObj;
  ..
end;

虽然我更喜欢不同的解决方案,比如你已经使用的解决方案。