12

Delphiアプリにクラスがあり、すべての文字列プロパティを''にリセットし、すべてのブールプロパティをFalseにリセットする簡単で動的な方法が必要です。Webで確認できる限り、ループを作成できるはずです。ある種のことですが、それをどのように行うかは私にはわかりません。

4

2 に答える 2

15

Delphi 2010(およびそれ以降)のユーザーの場合は、新しいRTTIユニット(rtti.pas)があります。これを使用して、クラスとそのプロパティに関する実行時情報を取得できます(デフォルトではパブリックプロパティですが、{$RTTI}コンパイラ指令を使用して保護フィールドとプライベートフィールドの情報を含めることができます)。たとえば、3つのパブリックフィールド(1つのブールフィールドと2つの文字列フィールド(そのうちの1つは読み取り専用))を持つ次のテストクラスがあります。

    TTest = class(TObject)
      strict private
        FString1 : string;
        FString2 : string;
        FBool : boolean;
      public
        constructor Create();
        procedure PrintValues();

        property String1 : string read FString1 write FString1;
        property String2 : string read FString2;
        property BoolProp : boolean read FBool write FBool;
    end;

constructor TTest.Create();
begin
    FBool := true;
    FString1 := 'test1';
    FString2 := 'test2';
end;

procedure TTest.PrintValues();
begin
    writeln('string1 : ', FString1);
    writeln('string2 : ', FString2);
    writeln('bool: ', BoolToStr(FBool, true));
end;

オブジェクトのすべてのプロパティを列挙し、その値をデフォルトに設定するには、以下のコードのようなものを使用できます。まず、TRttiContext構造を初期化する必要があります(レコードであるため、必須ではありません)。次に、オブジェクトに関するrtti情報を取得する必要があります。その後、プロパティをループしてフィルタリングできます(読み取り専用プロパティをスキップし、ブール値と攪拌以外)。文字列の種類が少ないことを考慮に入れてください:tkUString、tkStringなど(で見てTTypeKindくださいtypinfo.pas

    TObjectReset = record
      strict private
      public
        class procedure ResetObject(obj : TObject);  static;
    end;

{ TObjectReset }

class procedure TObjectReset.ResetObject(obj: TObject);
var ctx : TRttiContext;
    rt : TRttiType;
    prop : TRttiProperty;
    value : TValue;
begin
    ctx := TRttiContext.Create();
    try
        rt := ctx.GetType(obj.ClassType);

        for prop in rt.GetProperties() do begin
            if not prop.IsWritable then continue;

            case prop.PropertyType.TypeKind of
                tkEnumeration : value := false;
                tkUString :      value := '';
                else continue;
            end;
            prop.SetValue(obj, value);
        end;
    finally
        ctx.Free();
    end;
end;

テストする簡単なコード:

var t : TTest;
begin
    t := TTest.Create();
    try
        t.PrintValues();
        writeln('reset values'#13#10);
        TObjectReset.ResetObject(t);
        t.PrintValues();
    finally
        readln;
        t.Free();
    end;
end.

結果は

string1 : test1
string2 : test2
bool: True
reset values

string1 :
string2 : test2
bool: False

また、属性を見てください。imoプロパティ(リセットする必要がある)に何らかの属性をマークすることをお勧めします。デフォルト値は次のようになります。

[ResetTo('my initial value')]
property MyValue : string read FValue write FValue;

次に、でマークされているプロパティのみをフィルタリングできますResetToAttribute

于 2012-04-17T10:42:57.123 に答える
11

次のコードは、クラスの公開されたプロパティに対してのみ機能することに注意してください。また、以下の関数に渡されるクラスのインスタンスには、少なくとも公開されたセクションが定義されている必要があります。

古いスタイルのRTTIを使用して、公開された文字列プロパティ値を空の文字列に設定し、ブール値をFalseに設定する方法を次に示します。

Delphi 2009より古いDelphiを使用している場合は、tkUStringタイプが欠落している可能性があります。
その場合は、次のコードから削除してください。

uses
  TypInfo;

procedure ResetPropertyValues(const AObject: TObject);
var
  PropIndex: Integer;
  PropCount: Integer;
  PropList: PPropList;
  PropInfo: PPropInfo;
const
  TypeKinds: TTypeKinds = [tkEnumeration, tkString, tkLString, tkWString,
    tkUString];
begin
  PropCount := GetPropList(AObject.ClassInfo, TypeKinds, nil);
  GetMem(PropList, PropCount * SizeOf(PPropInfo));
  try
    GetPropList(AObject.ClassInfo, TypeKinds, PropList);
    for PropIndex := 0 to PropCount - 1 do
    begin
      PropInfo := PropList^[PropIndex];
      if Assigned(PropInfo^.SetProc) then
      case PropInfo^.PropType^.Kind of
        tkString, tkLString, tkUString, tkWString:
          SetStrProp(AObject, PropInfo, '');
        tkEnumeration:
          if GetTypeData(PropInfo^.PropType^)^.BaseType^ = TypeInfo(Boolean) then
            SetOrdProp(AObject, PropInfo, 0);
      end;
    end;
  finally
    FreeMem(PropList);
  end;
end;

簡単なテストコードを次に示します(プロパティを公開する必要があります。クラスに公開されたプロパティがない場合は、少なくとも空の公開セクションが存在する必要があります)。

type
  TSampleClass = class(TObject)
  private
    FStringProp: string;
    FBooleanProp: Boolean;
  published
    property StringProp: string read FStringProp write FStringProp;
    property BooleanProp: Boolean read FBooleanProp write FBooleanProp;
  end;

procedure TForm1.Button1Click(Sender: TObject);
var
  SampleClass: TSampleClass;
begin
  SampleClass := TSampleClass.Create;
  try
    SampleClass.StringProp := 'This must be cleared';
    SampleClass.BooleanProp := True;
    ResetPropertyValues(SampleClass);
    ShowMessage('StringProp = ' + SampleClass.StringProp + sLineBreak +
      'BooleanProp = ' + BoolToStr(SampleClass.BooleanProp));
  finally
    SampleClass.Free;
  end;
end;
于 2012-04-17T10:43:22.110 に答える