これを直接行う簡単な方法はありませんが、ソースと実行時のパフォーマンスの両方の効率を向上させるために使用できる手法があります。1 つの方法は、単純なヘルパーを作成して、特定のデータセットから適切な型の新しい値を初期化することです。
これにはレコード メソッドを使用できますが、キャッシュされたフィールド参照の使用が少し洗練されなくなるため、別の専用の初期化クラスを使用することをお勧めします。これは、効率のためにキャッシュされたフィールド参照を使用できます。
type
TPersonFDInitialiser = class
private
fldID: TIntegerField;
fldName: TStringField;
fldSurname: TStringField;
function get_NewValue: TPerson;
public
constructor Create(const aSource: TDataset);
property NewValue: TPerson read get_NewValue;
end;
コンストラクターでフィールド参照をキャッシュすると、各レコードの値を取得するたびに名前で検索する必要がなくなります。フィールド データ型に適切なクラスを使用すると、変換せずに各フィールド値に直接アクセスできます。
constructor TPersonFDInitialiser.Create(const aSource: TDataset);
begin
inherited;
fldID := aSource.FieldByName('id') as TIntegerField;
fldName := aSource.FieldByName('name') as TStringField;
fldSurname := aSource.FieldByName('surname') as TStringField;
end;
function TPersonFDInitialiser.get_NewValue: TPerson;
begin
result.ID := fldID.Value;
result.Name := fldName.Value;
result.Surname := fldSurname.Value;
end;
ご覧のとおり、これは膨大な量の作業ではありません (1 つのレコード値を明示的に初期化するのに必要な作業よりも少し多めです) が、反復的な使用をより洗練されたものにし、次のように書くのがより速くなります:
recno := 0;
init := TPersonFDInitialiser.Create(qryPersons);
try
while NOT qryPersons.EOF do
begin
persons[recno] := init.NewValue;
qryPersons.Next;
Inc(recno);
end;
finally
init.Free;
end;
個人の行を返し、 TPersonレコードの配列であるTFDQueryはどこqryPersons
にありますか(もちろん、適切にサイズ設定/縮小されています)。persons
TDataset基本クラス ( TFDQueryの最終的な派生元) を使用することで、この初期化クラスを、TDatasetの子孫からTPersonを初期化する必要がある任意の場所で使用できます。データセットは書かれているように一貫して名前が付けられていますが、必要に応じて初期化子をこの点でより柔軟にすることができます.これは練習問題として残されています.
もっと遠く行く
必要に応じて、このような初期化クラスのユーティリティを改善するために行うことができる多くの拡張機能があります。たとえば、次のようになります。
// To initialise a one-off, new TPerson value from a data set use a
// class function which will internally create an initialiser, obtain
// a new TPerson then destroy the initialiser for you:
//
// Note that this will need to be overloaded if it has the same name as
// the instance method (which must also then be overloaded):
class function TPersonFDInitialiser.NewValue(const aSource: TDataset): TPerson; overload;
// Implement a procedure which will initialise an existing TPerson value
// (by reference) with values from the current record.
//
// Again, a class procedure overload could be provided for one-off use
// taking care of creating and freeing the required initialiser:
class procedure TPersonFDInitialiser.SetPerson(const aSource: TDataset; var aPerson: TPerson); overload;
procedure TPersonFDInitialiser.SetPerson(var aPerson: TPerson); overload;
注: これらのSetPerson
メソッドは、get_NewValueが実際にそのメソッドを呼び出すような方法で実装できるため、実装全体で実際に値の設定を行うメソッドは 1 つだけになります。これにより、初期化コードの重複がなくなり、初期化クラスの信頼性と保守性が向上します。
function TPersonFDInitialiser.get_NewValue: TPerson;
begin
SetPerson(result);
end;
procedure TPersonFDInitialiser.SetPerson(var aPerson: TPerson);
begin
aPerson.ID := fldID.Value;
aPerson.Name := fldName.Value;
aPerson.Surname := fldSurname.Value;
end;