Delphi 2010の属性の詳細。例-データ検証

マウス 前回の記事「 Delphi 2010の属性の概要」で、属性の作成、適用、およびポーリングに関連する基本を示しました。 ただし、それらを使用できる理由の例は示しませんでした。

おそらく最も一般的な例は永続化であり、実際に誰かが同様の例をWings of Windの Webサイトに投稿しました。 データ検証(検証)のために、他のアプリケーションを紹介したいと思います。


以下に示すのは、属性を使用する単なる例であり、データをチェックするための完全なフレームワークではないことに注意してください。 既成のコードとしてではなく、概念のテストとして考えてください。

したがって、警告が終了したら、この場合、検証ルールを示すメタデータをクラスに追加できるようにしたいと思います。 Nameが空ではなく、 Ageの値の範囲が18から65の場合、 TPersonクラスをtrueと見なしたい場合があります。これを達成する1つの方法は、これらのルールを定義する属性を持つ対応するプロパティを提供し、次に使用するコードを使用することです転送されたオブジェクトを処理し、フルサイズの画像のすべてのクリックをチェックするためのRTTI 。 プロパティ値は、それらに付加された属性に対応します。


キャッチしましたか? さて、見てみましょう。

データ検証のいくつかの属性を定義して、異なるタイプでどのように機能するかを示しました。 検証コードをもう少し一般的にする小さな階層が作成されました。 文字列と数字の属性のみを作成しましたが、この考えは理解できます。

クラスの1つのソースコードを見てください。

MinimumIntegerAttribute = class (BaseIntegerValidationAttribute)
private
FMinimumValue: Integer;
public
constructor Create(MinimumValue : Integer; const FailureMessage : string );
function Validate(Value : Integer) : boolean; override ;
end;



コンストラクターには2つのパラメーターが含まれ、検証方法は非常に単純です(この場合、ルールは単純です)。 次のようになります。

function MinimumIntegerAttribute.Validate(Value: Integer): boolean;
begin
Result := Value >= FMinimumValue;
end;



これで属性を定義し、次のように使用できます。

TPerson = class
private
FName: String ;
FAge: Integer;
public
[NonEmptyString( 'Must provide a Name' )]
property Name : String read FName write FName;
[MinimumInteger(18, 'Must be at least 18 years old' )]
[MaximumInteger(65, 'Must be no older than 65 years' )]
property Age : Integer read FAge write FAge;
end;


はい、別のTPersonです。 あまりオリジナルではありません。

ご覧のとおり、 NameプロパティにNonEmtpyString属性を指定し、無効な値のエラーメッセージを追加しました。 また、 最小属性と最大属性を持つAgeプロパティにも注目しました。 おそらくもっと便利なのは、範囲の属性を定義することですが、2つの属性の1つのプロパティへの適用を示したかったのです。

この例では、チェックを行う簡単な関数を作成しました。

function Validate(Target : TObject; ErrorList : TStrings) : boolean;
var
ctx : TRttiContext;
t : TRttiType;
p : TRttiProperty;
a : TCustomAttribute;
begin
Result := True;

if not Assigned(Target) then
raise Exception.Create( 'Can' 't validate nil object' );

if not Assigned(ErrorList) then
raise Exception.Create( 'Can' 't validate with a nil ErrorList' );

ctx := TRttiContext.Create;
try
t := ctx.GetType(Target.ClassType);
for p in t.GetProperties do
for a in p.GetAttributes do
if a is BaseIntegerValidationAttribute then
begin
if not BaseIntegerValidationAttribute(a).Validate(p.GetValue(Target).AsInteger) then
ErrorList.Add(BaseValidationAttribute(a).FailureMessage);
end
else if a is BaseStringValidationAttribute then
begin
if not BaseStringValidationAttribute(a).Validate(p.GetValue(Target).AsString) then
ErrorList.Add(BaseValidationAttribute(a).FailureMessage);
end
finally
ctx.Free;
end;
end;


まず、オブジェクトの忠実なインスタンスがnilでないことを確認するためのチェックを行います。これはErrorlistにも当てはまり 、さまざまなメッセージを入れます。

次に、各プロパティについて、すべての属性を選択します。 属性のタイプに応じて、検証メソッドを呼び出し、検証する値を渡します。 Validate呼び出しが失敗した場合、 ErrorListにFailureMessageを追加します。

確かにあなたはもっと良くできる。 たとえば、チェック対象の型ごとにValidateメソッドを更新し、エラーをTStringsに出力するだけではいけないという事実は好ましくありません。 ValidationFailureオブジェクトのリストを提示する方がより正確である可能性があります。 しかし、45分間の作業で、これはアイデアを非常によく表していると思います。 サンプルコードはこちらからダウンロードできます。

永続性、データ検証、またはその他の目的で属性を使用する場合、これが役に立つことを願っています。
何人かの人々は、属性にポイントが見られないと言った。 おそらくあなたはそれらを研究し、しばらく放置して、彼らがあなたの頭の中で「成熟」できるようにするべきです。 彼らは、私たちの言語が私たちの考えを形づくると言います。これは単に、Delphiが過去に属性をサポートしていなかったためである可能性があります。 ジェネリック、匿名メソッド、およびそれらの前のインターフェースと同様に、それらを研究すればするほど、それらを使用するためのより多くのアイデアが現れることがわかります。

translate.by/you/more-attributes-in-delphi-2010/into-ru/trans
翻訳:©r3code、TDelphiBlog。

Source: https://habr.com/ru/post/J105776/


All Articles