如何在Delphi中获取具有Generic类型的对象列表

时间:2015-07-22 12:56:37

标签: delphi generics delphi-2010

我有几个课程如下:

Type
  TSystemBaseEntity = class(TPersistent)
  private 
    FID: integer;
  public
    property ID: integer read FID write FID;
  end;

  TProcessHeaderEntity = class(TSystemBaseEntity)
  private
    FHeaderDate: TDateTime;
  public
     property HeaderDate: TDateTime read FHeaderDate write FHeaderDate;
  end;

  TInvoiceHeaderEntity = class(TProcessHeaderEntity)
  private 
    FCustomerId: integer;
  public
    property CustomerId: integer read FCustomerId write FCustomerId;
  end;


  TRequestHeaderEntity = class(TProcessHeaderEntity)
  private 
    FWarehouseId: integer;
  public
    property WarehouseId: integer read FWarehouseId write FWarehouseId;
  end;


  TDataList = class(TPersistent)
  private
    FValues: TObjectList<TSystemBaseEntity>;
  protected
    function SetCaption: string; virtual;
  public
    procedure Execute; virtual; abstract;
    property Values: TObjectList<TSystemBaseEntity> read FValues;
  end;

  TInvoice = class(TDataList)
  public
    procedure Execute; override;
  end;

如何通过属性获取继承自 TSystemBaseEntity 的泛型类型的对象列表?

例如,发票清单(TInvoiceHeaderEntity)或请求清单(TRequestHeaderEntity)以及对其属性的访问权。

1 个答案:

答案 0 :(得分:4)

如果您想要一个包含TSystemBaseEntity的特定子类的TDataList,请将TDataList定义为通用类,并使用type constraint

这被定义为

  TDataList<T:TSystemBaseEntity> = class(TPersistent)
  private
    FValues: TObjectList<T>;
  protected
    function SetCaption: string; virtual;
  public
    procedure Execute; virtual; abstract;
    property Values: TObjectList<T> read FValues;
  end;

用作

  TInvoice = class(TDataList<TInvoiceHeaderEntity>)
  public
    procedure Execute; override;
  end;

procedure TInvoice.Execute
var
  InvoiceHeader: TInvoiceHeaderEntity;
begin
  for InvoiceHeader in Values do
    ...
end;

如果您想要一个类型为TDataList且成员为TObjectList<TSystemBaseEntity>,则不能将其用作TObjectList<TInvoiceHeaderEntity>等。请查看Wikipedia作为介绍,还要考虑在这样的计划下允许以下内容:

procedure DoBadThingsWithGenerics(aDataList: TDataList);
var
  myInvoices: TObjectList<TInvoiceHeaderEntity>
  myRequests: TObjectList<TRequestHeaderEntity>
  Request: TRequestHeaderEntity;
begin
  myInvoices := aDataList.Values<TInvoiceHeaderEntity>;
  myRequests := aDataList.Values<TRequestHeaderEntity>;

  // Some code ...

  myInvoices.Add( TInvoiceHeaderEntity.Create );

  // Some more code...

  for Request in myRequests do
    // Oops, we have a TInvoiceHeaderEntity pretending to be a TRequestHeaderEntity
end;

您可以在此处执行一个过程,该过程采用了一个新的后代类型列表,过滤了值列表中适当类型的元素,并将它们添加到新列表中。

procedure TDataList.FilterByType<S:TSystemBaseEntity> ( intoList: TObjectList<S> );
var
  Value: TSystemBaseEntity;
begin
  for Value in Values do
    if Value is S then
      intoList.Add( Value as S );
end;