如何在项目之间共享记录结构,略有不同?

时间:2016-01-04 14:18:19

标签: arrays delphi delphi-xe7

我有2个项目可以处理相同的数据,不同的流程。主阵列几乎完全相同,略有变化,如:

// Project 1

TData1 = record
  A:string;
  B:integer;
  C:word;
  ...
end;

// Project 2

TData1 = record
  A:string;
  B:integer;
  C:word;
  ...
  XMLNode:TXMLNode; // Extra value needed in Project 2, not needed in Project 1
end;

我想在项目之间共享众多阵列。我想保持相同的数组结构,以便我可以复制和粘贴任何需要在两个项目中实现的未来更改。 有没有办法保持记录相同而略有差异?

我在考虑这样的事情:

    // in Project 1:

    TExtras = record
    end;

    // in Project 2:

    TExtras = record
      XMLNode:TXMLNode;
    end;

    // shared - in both projects

    TData1 = record
      A:string;
      B:integer;
      C:word;
      ...
      Extras:TExtras; // different extra fields based on project needs
    end;

我可以在Project2中使用Data1.Extras.XMLNode访问字段的其他字段中添加其他字段。不确定这是否是未来的实施。

目标是有一天将所有共享结构放入共享单元,一个维护点,不再复制和粘贴。我需要数组来保持作为简单数组(array of TData1TArray<TData1>)的灵活性,因此我无法进入复杂的实现,这将限制轻松复制,排序,区分,操作数据的选项。 ..

这是正确的做法吗?有更好的想法吗?

修改:

这两个项目都使用相同的数据,所以他们都阅读相同的数据来源&#39;文件,但产生不同的最终结果。现在我有很多阵列,其中99%用于两个项目,相同功能的相同目的。 但是现在,当我在一个或另一个项目上工作时,添加新的记录字段,使用新字段的新功能,如果我不立即同步结构和新功能,那么几周后我会发生需要在项目2中执行相同的操作,我将创建具有不同名称和不同函数名称的新字段。所以,当我最终在项目之间复制一些复杂的功能时,我发现它们只是因为命名不同而不匹配。

编辑2:

从所有评论和建议中我决定采用另一种方式:在共享单元中共享通用数据结构和代码,并在项目2中创建具有额外记录字段的其他数组。我将创建这些链接到主数据的新数组数组,有:

// shared data 
TData1 = record
  A:string;
  B:integer;
  C:word;
  ...
end;

Data1:TArray<TData1>;

// additional in Project 2
TDataExtra = record
  DataIdx:integer;// link to TData1
  XMLNode:TXMLNode;
  ...
end; 

DataExtras:TArray<TDataExtra>;

可以轻松访问每个Data1记录的XMLNode值:

fGetXMLNode(i); // where i is index in Data1 array and function will return XMLNode

我相信,我可以保留共享单元并为任何阵列添加任何额外功能,只需最少的额外工作,这比维护2数据结构和代码的成本更低。

这会是更好的解决方案吗?

3 个答案:

答案 0 :(得分:2)

如果没有完整的上下文,很难说哪种解决方案最好/更好,但这里有一些其他方法可以实现相同的目标。

条件定义

TData1 = record
  A:string;
  B:integer;
  C:word;
  [...]
{$IFDEF NEEDXMLNODEINTDATA1}
  XMLNode:TXMLNode; // different extra fields based on project needs
{$ENDIF}
end;

使用新结构

在第二个应用程序中使用不同的结构。对于大多数情况,我希望这是正确的方法。

TData1Node = record
  Data1 : TData1;
  XMLNode : TXMLNode;
end;

始终包含XMLNode

因为它只是一个指针,除非你的应用程序中有一些荒谬的记录,否则它几乎不会记录内存使用情况。

答案 1 :(得分:2)

Pascal没有void / Unit数据类型,你仍然可以模拟它。 编译器并不总是对它感觉良好,在某些路径中它只是没有假设/检查在某些极端情况下SizeOf(someType)可能为零。

但是,如果你真的需要挤压Project 2中的每个最后一个字节,同时保持与Project 1共享的源代码,可以使用这个丑陋的黑客:

文件Project_1.inc

{$IFnDEF THIS_IS_PROJECT_1}
halt compilation! wrong setup!!!
{$EndIf}

{$IFDEF THIS_IS_PROJECT_2}
halt compilation! wrong setup!!!
{$EndIf}

type TDataPayload = TXMLNode;

文件Project_2.inc

{$IFnDEF THIS_IS_PROJECT_2}
halt compilation! wrong setup!!!
{$EndIf}

{$IFDEF THIS_IS_PROJECT_1}
halt compilation! wrong setup!!!
{$EndIf}

type REmpty = packed record end;

type TDataPayload = REmpty;

// after compilation - call `assert(SizeOf(TDataPayload) = 0);`

文件CommonDataType.pas

{$IfDef THIS_IS_PROJECT_1}
  {$INCLUDE Project_1.inc}
{$EndIf}

{$IfDef THIS_IS_PROJECT_2}
  {$INCLUDE Project_2.inc}
{$EndIf}

TData1 = 
{$IFDEF THIS_IS_PROJECT_2}
  packed
{$EndIf}
  record
    A:string;
    B:integer;
    C:word;
  ...
    Payload: TDataPayLoad;
  end;

话虽如此,您在项目2中通过type TXMLNode=byte兼容性存根不能浪费单个字节的评估对我来说似乎非常可疑。这是因为:

  1. 你使用快速记忆填充record而不是慢速字节压缩packed record
  2. 你使用TXMLNode,即使在不同的项目中 - 每个TObject实例都会占用几十个字节,指向RTTI的指针,指向VMT的指针,支持堆管理器中的帧....在记录中指向它的指针就是这样另外占用4或8个字节。你不能承受一个额外的字节而不是所有的???来吧!
  3. 您的A:string;每个记录中每个指针花费4(或8)个字节,然后再将{12}个字节作为StringRec标头,然后是未知的预先分配的简单内容缓冲区字符串内容,然后两个额外的字节用于尾随#0,然后支持堆管理器中的数据结构。仍然只有type TXMLNode=boolean存根的一个额外字节太多了???
  4. 如果您的应用程序性能/正确性仅依赖于每个数据帧一个额外字节,这也意味着,由于用户生成的数据比平常多5%,您的应用程序也会中断。期。如果要相信您的评估,那么您的应用程序已经达到了标准,已超出算法/设计限制。并且应该重新构建以使用内存未绑定算法。一个简单的例子 - 您可以使用磁盘上的流式排序,而不是使用内存中的Quicksort,它具有相同的最坏情况复杂性,但只需要4个数据帧的内存。

答案 2 :(得分:2)

简单的解决方案是保持两个项目之间共享的数据结构和相关功能,并添加包含特定于每个项目的附加数据的其他数组。 它将为使用额外的数组带来更多的工作,但会保持共享代码真正共享。

因此,与其他anwers中提出的新类或IFDef不同,链接到主数据的简单额外数组是该问题的最佳选择:

// shared main data through both projects
TData1 = record
  A:string;
  B:integer;
  C:word;
  ...
end;

Data1:TArray<TData1>;

// additional in Project 2
TDataExtra = record
  DataIdx:integer;// link to TData1
  XMLNode:TXMLNode;
  ...
end; 

DataExtras:TArray<TDataExtra>;

使用此解决方案,任何其他数组(如DataExtras或其他阵列的任何其他字段)都可以轻松添加,扩展,而无需更改共享代码。共享代码很容易维护,因为它只保存主要数据,而不是只有一个项目