delphi - 如何防止为泛型类生成重复的代码?

标签 delphi generics

Delphi 有一个为泛型类重复代码的坏习惯。即使代码确实相同,因为泛型类型是相似的。
我想防止重复存储不同的类。
在我的通用容器中,我仅在需要时使用 Free 进行清理。

假设我有一个像这样的通用容器:

unit Unit1;

interface

uses Generics.Collections;

type
  TMyContainer<T> = class(TObject)
  strict private
    FData: TList<T>;
  public
    constructor Create; virtual;
  end;

我知道T通常是一个对象。因为所有对象实际上都是 TObject 我不希望我的容器为不同类型的对象创建重复的通用代码。

下面的技巧可以防止重复吗?

A- 用类函数替换构造函数:

unit Unit2;

uses Unit1;

type
  TMyContainer<T> = class(Unit1.TMyContainer<T>)
  public
    class function Create: TMyContainer<T>; static;
  end;

B:实现类函数Create,如下所示:

class function TMyContainer<T>.Create: TMyContainer<T>;
var
  X: TObject;
begin
  if GetTypeKind(T) = tkClass then begin
    X:= Unit1.TMyContainer<TObject>.Create;
  end else begin
    X:= Unit1.TMyContainer<T>.Create;
  end;
  TObject(Result):= X;
end;

这个技巧是否可以防止编译器为不同类型的对象生成重复的代码,或者是否会因为我使用了不正确的假设而失败?
请注意,我不想使用非通用存储来存储我的数据。

完整示例代码如下

unit Unit49;

interface

uses Generics.Collections;

type
  TMyContainer<T> = class(TObject)
  strict private
    FData: TList<T>;
  public
    constructor Create; virtual;
  end;

implementation

constructor TMyContainer<T>.Create;
begin
  inherited Create;
  FData:= TList<T>.Create;
end;

end.

示例程序

program Project85;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  Unit49 in 'Unit49.pas';

type
  TMyContainer<T> = class(Unit49.TMyContainer<T>)
  public
    class function Create: TMyContainer<T>; static;
  end;

{ TMyContainer<T> }

class function TMyContainer<T>.Create: TMyContainer<T>;
var
  Y: T;
  X: TObject;
begin
  if GetTypeKind(T) = tkClass then begin
    X:= Unit49.TMyContainer<TObject>.Create;
  end else begin
    X:= Unit49.TMyContainer<T>.Create;
  end;
  TObject(Result):= X;
end;

var
  A: TMyContainer<TObject>;
  B: TMyContainer<TLanguages>;

begin
  A:= TMyContainer<TObject>.Create;
  B:= TMyContainer<TLanguages>.Create;
  readln;
end.

最佳答案

Will this trick work to prevent the compiler from generating duplicate code for different types of objects, or will this fail because I'm using incorrect assumptions?

不,这不会起作用。

基本上,编译器遵循您的 T遍历整个类层次结构并将其替换为特定类型。

首先,您将拥有单独的 TList<T>TObject 生成代码和TLanguages因为你的容器被声明为 FData: TList<T> , 然后 你的技巧集合也继承自通用 T TMyContainer<T> = class(Unit49.TMyContainer<T>)并且类函数中的整个代码基本上是无用的。

编译器将为 Unit49.TMyContainer<TLanguages> 生成重复代码类以及 Unit49.TMyContainer<TObject>类。

从您的示例中很难说出您想要避免哪些代码重复。如果容器类像您在示例中编写的那样简单,那么所有代码​​重复都将来自 TList<T>类(class)。如果您想避免这种情况,则没有简单的出路。

您的问题的部分原因在于您有 T那可以是任何东西。很难对其进行优化。您可以获得的最大优化是使用 array of T用于存储数据,然后委派操作函数,您可以在其中使用 TObject作为所有类和普通类的基础 T为他人。

您能从上面获得多少 yield 还取决于您使用哪个Delphi版本,因为在最新版本中TList<T>已使用类似技术进行了一些优化。

但是,如果您可以为类和其他类型拥有单独的容器,那么您可以实现 TObject 的代码折叠和后代容器使用 TObjectList<TObject> (或者甚至是 Windows 上的非泛型 TObjectList)用于存储所有特定类并通过类型转换实现您需要的任何类型安全函数的瘦包装函数。当然,每个这样的函数都会为每种特定类型生成一些代码,但由于它们只是类型转换包装器,因此代码量不会像使用完整的 TList<T> 那样多。对于每个类类型。

  TMyObjectContainer<T> = class(TObject)
  strict private
    FData: TObjectList<TObject>; 
  public
    constructor Create; virtual;
    destructor Destroy; override;  
    function Data(index: integer): T;
  end;

constructor TMyObjectContainer<T>.Create; 
begin
  inherited;
  FData := TObjectList<TObject>.Create;
end; 

constructor TMyObjectContainer<T>.Create; 
begin
  FData.Free;
  inherited;
end; 

function TMyObjectContainer<T>.Data(index: integer): T;
begin
  Result := T(FData.Items[index]);
end;

关于delphi - 如何防止为泛型类生成重复的代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37364611/

相关文章:

c++ - 编写从C++应用程序链接的Delphi DLL:访问C++接口(interface)成员函数会导致访问冲突

c# - 如何指定不实现特定接口(interface)的类型参数?

c# - 泛型<T>() 与泛型(System.Type)。泛型与反射

java - 具有相同的删除功能,但两者都不会覆盖仅在一种情况下出现的其他警告

delphi - 从汇编例程访问 Delphi 记录、类等之后的第一个字节

Delphi 6 和 Indy SSL 连接不工作

Java 泛型不适用于参数问题

java - 如何返回通用枚举的枚举元素列表?

delphi - 如何从 delphi2007 win32 刻录 CD/DVD

delphi - 错误: Object Was Open - Delphi