2

我知道的非常不时髦的标题。

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

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

AProcessOrderArray = array of TProcessOrderRecord;

Initialise 倾向于调用一个构造函数,该构造函数将填充宿主对象中的一个字段。

Process 将是对象上的一个过程,它将为每个与 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 的实例也是 nil。有没有什么干净的方法可以让记录在调用时而不是在第一次分配时指向 FMyObj 的实例?

目前我已经在宿主对象上使用了“调用者”方法,然后可以在需要时调用 FMyObj 实例,但这会创建一个包含许多单行方法的相当臃肿的对象。

编辑以澄清/复杂化问题

有时一个实例FObj可以处理不止一种类型的记录(通常如果它们具有主从关系)。在这种情况下,InitialiseProcedure第一个记录类型将创建FObjFinaliseProcedure第二个记录将释放FObj,并且每个记录ProcessProcedure可以引用FObj(do1do2) 的不同过程。

4

2 回答 2

3

目前我已经在宿主对象上使用了“调用者”方法,然后可以在需要时调用 FMyObj 实例,但这会创建一个包含许多单行方法的相当臃肿的对象。

这是正确的解决方案。由于实例在初始化时不可用,您别无选择。

当您使用时,of object您正在定义一种称为方法指针的东西。当您分配给方法指针类型的变量时,实例在分配点被捕获。与方法指针关联的实例没有动态解析的机制。实现这一目标的唯一方法是使用运行时委托,这是您当前正在做的。通常情况下,使用另一层间接来解决问题!

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

于 2013-03-06T17:29:03.313 回答
1

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

var
  A: TProcessOrderRecord;

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

尽管我更喜欢不同的解决方案,例如您已经使用的解决方案。

于 2013-03-06T18:04:12.740 回答