2009-04-30 30 views
13

yesterdayからの私の質問は、おそらく完全に明確ではありませんでしたし、私は私が望んでいた答えが得られませんでした、私はより一般的な方法でそれを策定しようとしますので:条件付き行動

がありますExplicit条件文を使うか、ある種の特殊化を使用して、インスタンス化されたジェネリック型の実際の型に基づいて特別な振る舞いを実装する方法?擬似コード:

TGenericType <T> = class 
    function Func : Integer; 
end; 
... 
function TGenericType <T>.Func : Integer; 
begin 
    if (T = String) then Exit (0); 
    if (T is class) then Exit (1); 
end; 
... 
function TGenericType <T : class>.Func : Integer; 
begin 
Result := 1; 
end; 
function TGenericType <String>.Func : Integer; 
begin 
Result := 0; 
end; 

答えて

19

TypeInfo(T) = TypeInfo(string)を使用してRTTIにフォールバックできます。何かがクラスであるかどうかを調べるために、PTypeInfo(TypeInfo(T))^.Kind = tkClassのようなものを使うことができます。

PTypeInfoタイプとtkClass列挙メンバは、TypInfoユニットで定義されています。誰かが私が私のために

class function RTTIUtils.GetDeepSize <T> (Variable : T) : Integer; 
var 
    StringLength   : Integer; 
    Ptr     : PInteger; 
begin 
if (TypeInfo (T) = TypeInfo (String)) then 
    begin 
    Ptr := @Variable; 
    Ptr := PInteger (Ptr^); 
    Dec (Ptr); 
    StringLength := Ptr^; 
    Result := StringLength * SizeOf (Char) + 12; 
    end 
else 
    Result := 0; 
end; 

「文字列に対して特別な処理でワーストケースサイズ」私を実装んでしたどのように関心がある場合

+1

+1ありがとう!それはまさに私が探していたものです!あなたが私の元のアイデアのファンではない場合でも) – jpfollenius

1

C#で、あなたは私はあなたの他の質問(あなたdidntのリンクを見たhavent

(T = String) 

または

(T is class) 

あなたのような何かを行うことができるようになるtypeof(T)を行うことができますそれに)、あなたは何ですか本当にをお探しですか?一般的に、あなたがやっているようなifやswitchを使って、型や型コードの条件付きを行うのは、一般的に、コンテキストやカスタマイズされたインターフェースや抽象関数をもっているのが最も良い方法です。

+0

他の質問へのリンクを追加しました。基本的には、サイズの概算をバイト単位で求めています。他のタイプとは違う文字列を扱いたい – jpfollenius

+0

これを落とした人は、あなたの理由をコメントしてください。私はそれが妥当な答えだったと思う – jpfollenius

+0

ああ、あなたは古いSOのカルマシステムは時々楽しく驚き、感謝!あなたの返事を自分自身にアップアップした(しかし、最初は質問をアップアップしていなかった:P) –

3

が、これは手元に仕事をしていません。すべての貢献者に感謝します!

1

TypeInfo(T)は正しい方法です。さらに、TTypeDataレコードのようなTypInfoユニットのすべてのものを使用して、汎用タイプの代わりに使用するタイプの特定のプロパティを特定することができます。 Tの代わりに使用される現在の型を決定するときは、ポインタのトリックを使用して変数の値を取得できます。

ここでは、列挙型を汎用として受け入れるサンプルコードを示します。それと列挙プロシージャ内のローカル型として宣言されてはならない(=(第一= 1)、第二、第三の

TEnumWontWorkような固定値なし)のみ通常列挙のために働くことに注意してください。このような場合、コンパイラは列挙型のTypeInfoを生成しません。使い方の

type 
    // Sample generic class that accepts any enumeration type as T 
    TEnumArr<T> = class 
    strict private 
    fArr: array of Byte; 
    fIdxType: TOrdType; 
    function IdxToInt(idx: T): Int64; 
    procedure Put(idx: T; Val: Byte); 
    function Get(idx: T): Byte; 
    public 
    constructor Create; 
    property Items[Index: T]: Byte read Get write Put; default; 
    end; 

constructor TEnumArr<T>.Create; 
var 
    pti: PTypeInfo; 
    ptd: PTypeData; 
begin 
    pti := TypeInfo(T); 
    if pti = nil then 
    Error('no type info'); 
    // Perform run-time type check 
    if pti^.Kind <> tkEnumeration then 
    Error('not an enum'); 
    // Reach for TTypeData record that goes right after TTypeInfo record 
    // Note that SizeOf(pti.Name) won't work here 
    ptd := PTypeData(PByte(pti) + SizeOf(pti.Kind) + (Length(pti.Name)+1)*SizeOf(AnsiChar)); 
    // Init internal array with the max value of enumeration 
    SetLength(fArr, ptd.MaxValue); 
    // Save ordinal type of the enum 
    fIdxType := ptd.OrdType; 
end; 

// Converts index given as enumeration item to integer. 
// We can't just typecast here like Int64(idx) because of compiler restrictions so 
// use pointer tricks. We also check for the ordinal type of idx as it may vary 
// depending on compiler options and number of items in enumeration. 
function TEnumArr<T>.IdxToInt(idx: T): Int64; 
var 
    p: Pointer; 
begin 
    p := @idx; 

    case fIdxType of 
    otSByte: Result := PShortInt(p)^; 
    otUByte: Result := PByte(p)^; 
    otSWord: Result := PSmallInt(p)^; 
    otUWord: Result := PWord(p)^; 
    otSLong: Result := PLongInt(p)^; 
    otULong: Result := PLongWord(p)^; 
    end; 
end; 

function TEnumArr<T>.Get(idx: T): Byte; 
begin 
    Result := fArr[IdxToInt(idx)]; 
end; 

procedure TEnumArr<T>.Put(idx: T; Val: Byte); 
begin 
    fArr[IdxToInt(idx)] := Val; 
end; 

サンプル:取得)T

2の一般​​的な小道具とTのためのTypeInfoを取得

1):履歴書として

type 
    TEnum = (enOne, enTwo, enThree); 
var 
    tst: TEnumArr<TEnum>; 
begin 
    tst := TEnumArr<TEnum>.Create; 
    tst[enTwo] := $FF; 
    Log(tst[enTwo]); 

、私はここ3つのトリックを使用しましたTの型データTの詳細小道具T

3)ポインタの魔法を使ってparameの値を得るT型として与えられている。

このヘルプが必要です。