ジェネリックスでは渡される型パラメータに関する制約を指定することができます。
ジェネリックスの制約 - RAD Studio XE3
ここで制約としてインタフェース型またはクラス型を指定すると型パラメータは必然的にそのクラス型、インタフェース型になります。またconstructorを指定すると型パラメータはクラス型になります(レコード型はパラメータを持たないコンストラクタを定義できないため)。classを指定するとこれもまたクラス型、インタフェース型になります(ヘルプ参照)。
では最後に残ったrecordを指定(レコード指定)した場合、型パラメータに許される型はレコード型だけなのでしょうか?実際にはレコード型だけではなく、いわゆる値型(参照型ではないもの)であればいいようで、IntegerやCardinal、あるいは部分範囲型や列挙型も指定することができます。
type TConstraintTest<T: record> = record class procedure TestProc(Value: Integer); static; end; class procedure TConstraintTest<T>.TestProc(Value: Integer); begin { No operation } end;このようなジェネリックスを定義すると、
type TTestRange = 1..5; TTestEnum = (One, Two, Three); begin TConstraintTest<TPoint>.TestProc(0); TConstraintTest<Integer>.TestProc(0); TConstraintTest<Cardinal>.TestProc(0); TConstraintTest<TTestRange>.TestProc(0); TConstraintTest<TTestEnum>.TestProc(0); end;これらはすべて正しくコンパイルされます。
ただしString型は参照型でありながらクラス型ではないため、constructor以外の制約を指定された型パラメータにStringを指定するとコンパイルエラーになります("class"を指定すると
E2511 型パラメータ 'T' はクラス型が必要です、"record"を指定すると
E2512 型パラメータ 'T' は非 null 値型が必要ですとなる)。つまり文字列型を受け入れるためには型パラメータに制約を指定しないか、constructor制約を指定するかのいずれかが必要ということになります。
元ねたはDelphi XE2 Foundations。
2013/07/03追記: constructor制約については細川さんによる考察が参考になります。
0 件のコメント:
コメントを投稿