数组 – 给定一个记录数组,如何获得一个表示每个字段的数组的数组?

前端之家收集整理的这篇文章主要介绍了数组 – 给定一个记录数组,如何获得一个表示每个字段的数组的数组?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我必须翻译一些Fortran 90代码并找到一个有趣的语言功能.

例如,它们定义以下类型和动态数组变量:

TYPE WallInfo
  CHARACTER(len=40) :: Name
  REAL              :: Azimuth
  REAL              :: Tilt
  REAL              :: Area
  REAL              :: Height
END TYPE WallInfo

TYPE(WallInfo),ALLOCATABLE,DIMENSION(:) :: Wall

稍后在代码中,他们调用一个函数

CALL HeatFlow(Wall%Area,Wall%Azimuth)

作为一名Delphi程序员,这让我感到有些不同,因为Wall是一系列记录!

从例程中的用法来看,很明显Fortran可以将记录数组中的字段作为自己的数组进行投影.

SUBROUTINE HeatFlow( Area,Azimuth )
  REAL,INTENT(IN),DIMENSION(:) :: Area
  REAL,DIMENSION(:) :: Azimuth

有没有人知道是否有办法用Delphi(我使用的是2010版)?

我可以编写一个函数来将记录值提取为数组,但这有点单调乏味,因为我必须为每个字段编写一个专用例程(并且有很多).

我希望Delphi 2010中有一些我错过的语言功能.

解决方法

使用扩展RTTI,可以创建一个通用函数,该函数将数组和字段名称作为输入,并使用数组的RTTI仅提取该字段的值,并使用正确的数据类型创建具有它们的新数组.

以下代码适用于XE2:

uses
  System.SysUtils,System.Rtti;

type
  FieldArray<TArrElemType,TFieldType> = class
  public
    class function Extract(const Arr: TArray<TArrElemType>; const FieldName: String): TArray<TFieldType>;
  end;

class function FieldArray<TArrElemType,TFieldType>.Extract(const Arr: TArray<TArrElemType>; const FieldName: String): TArray<TFieldType>;
var
  Ctx: TRttiContext;
  LArrElemType: TRttiType;
  LField: TRttiField;
  LFieldType: TRttiType;
  I: Integer;
begin
  Ctx := TRttiContext.Create;
  try
    LArrElemType := Ctx.GetType(TypeInfo(TArrElemType));
    LField := LArrElemType.GetField(FieldName);
    LFieldType := Ctx.GetType(TypeInfo(TFieldType));
    if LField.FieldType <> LFieldType then
      raise Exception.Create('Type mismatch');
    SetLength(Result,Length(Arr));
    for I := 0 to Length(Arr)-1 do
    begin
      Result[I] := LField.GetValue(@Arr[I]).AsType<TFieldType>;
    end;
  finally
    Ctx.Free;
  end;
end;

.

type
  WallInfo = record
    Name: array[0..39] of Char;
    Azimuth: Real;
    Tilt: Real;
    Area: Real;
    Height: Real;
  end;

procedure HeatFlow(const Area: TArray<Real>; const Azimuth: TArray<Real>);
begin
  // Area contains (4,9) an Azimuth contains (2,7) as expected ...
end;

var
  Wall: TArray<WallInfo>;
begin
  SetLength(Wall,2);

  Wall[0].Name := '1';
  Wall[0].Azimuth := 2;
  Wall[0].Tilt := 3;
  Wall[0].Area := 4;
  Wall[0].Height := 5;

  Wall[1].Name := '6';
  Wall[1].Azimuth := 7;
  Wall[1].Tilt := 8;
  Wall[1].Area := 9;
  Wall[1].Height := 10;

  HeatFlow(
    FieldArray<WallInfo,Real>.Extract(Wall,'Area'),FieldArray<WallInfo,'Azimuth')
    );
end;

猜你在找的Delphi相关文章